laravel / nova-issues

554 stars 34 forks source link

4.16 breaking BelongsToMany relations #4938

Closed Synchro closed 2 years ago

Synchro commented 2 years ago

Description:

I have some reciprocal BelongsToMany model relations (with a custom model for the join) that are set up like this:

    public function products(): belongsToMany
    {
        return $this->belongsToMany(Product::class)
            ->using(ProductScan::class)
            ->withPivot('is_carrier', 'orderable_id');
    }
    public function scans(): BelongsToMany
    {
        return $this->belongsToMany(Scan::class)
            ->using(ProductScan::class)
            ->withPivot('is_carrier', 'orderable_id');
    }

In Nova:

            BelongsToMany::make('Products')
                ->searchable()
                ->fields(
                    function ($request, $relatedModel) {
                        return [
                            Boolean::make('Is carrier'),
                        ];
                    }
                ),

and

            BelongsToMany::make('Scans')
                ->searchable()
                ->fields(
                    function ($request, $relatedModel) {
                        return [
                            Boolean::make('Is carrier'),
                        ];
                    }
                ),

In 4.15, this works fine – in my scans resource I see a list of products, and vice versa. In 4.16 I get a crash:

[2022-10-18 09:04:13] local.ERROR: Call to a member function scans() on null {"userId":1,"exception":"[object] (Error(code: 0): Call to a member function scans() on null at vendor/laravel/nova/src/ResolvesFields.php:803)
[stacktrace]
#0 vendor/laravel/nova/src/ResolvesFields.php(962): Laravel\Nova\Resource->pivotFieldsFor(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest), 'scans')
#1 vendor/laravel/framework/src/Illuminate/Collections/Traits/EnumeratesValues.php(482): Laravel\Nova\Resource->Laravel\Nova\{closure}(Array, true)
#2 vendor/laravel/nova/src/ResolvesFields.php(119): Illuminate\Support\Collection->when(true, Object(Closure))
#3 vendor/laravel/nova/src/ResolvesFields.php(150): Laravel\Nova\Resource->peekableFieldsCollection(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#4 vendor/laravel/nova/src/Fields/Peekable.php(85): Laravel\Nova\Resource->peekableFieldsCount(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#5 vendor/laravel/nova/src/Fields/BelongsTo.php(533): Laravel\Nova\Fields\BelongsTo->hasFieldsToPeekAt(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#6 vendor/laravel/framework/src/Illuminate/Support/helpers.php(377): Laravel\Nova\Fields\BelongsTo->Laravel\Nova\Fields\{closure}(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#7 vendor/laravel/nova/src/Fields/BelongsTo.php(542): with(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest), Object(Closure))
#8 [internal function]: Laravel\Nova\Fields\BelongsTo->jsonSerialize()
#9 vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(87): json_encode(Array, 0)
#10 vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\Http\JsonResponse->setData(Array)
#11 vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(32): Symfony\Component\HttpFoundation\JsonResponse->__construct(Array, 200, Array, false)
#12 vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(99): Illuminate\Http\JsonResponse->__construct(Array, 200, Array, 0)
#13 vendor/laravel/nova/src/Http/Resources/Resource.php(41): Illuminate\Routing\ResponseFactory->json(Array)
#14 vendor/laravel/nova/src/Http/Controllers/ResourceIndexController.php(19): Laravel\Nova\Http\Resources\Resource->toResponse(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#15 vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): Laravel\Nova\Http\Controllers\ResourceIndexController->__invoke(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest), 'products')
#16 vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): Illuminate\Routing\Controller->callAction('__invoke', Array)
#17 vendor/laravel/framework/src/Illuminate/Routing/Route.php(262): Illuminate\Routing\ControllerDispatcher->dispatch(Object(Illuminate\Routing\Route), Object(Laravel\Nova\Http\Controllers\ResourceIndexController), '__invoke')
#18 vendor/laravel/framework/src/Illuminate/Routing/Route.php(205): Illuminate\Routing\Route->runController()
#19 vendor/laravel/framework/src/Illuminate/Routing/Router.php(721): Illuminate\Routing\Route->run()
#20 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\Routing\Router->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#21 vendor/laravel/nova/src/Http/Middleware/Authorize.php(18): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#22 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel\Nova\Http\Middleware\Authorize->handle(Object(Illuminate\Http\Request), Object(Closure))
#23 vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(44): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#24 vendor/laravel/nova/src/Http/Middleware/Authenticate.php(31): Illuminate\Auth\Middleware\Authenticate->handle(Object(Illuminate\Http\Request), Object(Closure), 'web')
#25 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel\Nova\Http\Middleware\Authenticate->handle(Object(Illuminate\Http\Request), Object(Closure))
#26 vendor/laravel/nova/src/Http/Middleware/BootTools.php(20): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#27 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel\Nova\Http\Middleware\BootTools->handle(Object(Illuminate\Http\Request), Object(Closure))
#28 vendor/laravel/nova/src/Http/Middleware/DispatchServingNovaEvent.php(24): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#29 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel\Nova\Http\Middleware\DispatchServingNovaEvent->handle(Object(Illuminate\Http\Request), Object(Closure))
#30 vendor/inertiajs/inertia-laravel/src/Middleware.php(92): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#31 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Inertia\Middleware->handle(Object(Illuminate\Http\Request), Object(Closure))
#32 vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#33 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Routing\Middleware\SubstituteBindings->handle(Object(Illuminate\Http\Request), Object(Closure))
#34 vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(78): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#35 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\VerifyCsrfToken->handle(Object(Illuminate\Http\Request), Object(Closure))
#36 vendor/laravel/framework/src/Illuminate/Session/Middleware/AuthenticateSession.php(58): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#37 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Session\Middleware\AuthenticateSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#38 vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#39 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\View\Middleware\ShareErrorsFromSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#40 vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(121): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#41 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))
#42 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Session\Middleware\StartSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#43 vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#44 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle(Object(Illuminate\Http\Request), Object(Closure))
#45 vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(67): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#46 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Cookie\Middleware\EncryptCookies->handle(Object(Illuminate\Http\Request), Object(Closure))
#47 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#48 vendor/laravel/framework/src/Illuminate/Routing/Router.php(723): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#49 vendor/laravel/framework/src/Illuminate/Routing/Router.php(698): Illuminate\Routing\Router->runRouteWithinStack(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request))
#50 vendor/laravel/framework/src/Illuminate/Routing/Router.php(662): Illuminate\Routing\Router->runRoute(Object(Illuminate\Http\Request), Object(Illuminate\Routing\Route))
#51 vendor/laravel/framework/src/Illuminate/Routing/Router.php(651): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
#52 vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(167): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#53 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}(Object(Illuminate\Http\Request))
#54 vendor/laravel/nova/src/Http/Middleware/ServeNova.php(23): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#55 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel\Nova\Http\Middleware\ServeNova->handle(Object(Illuminate\Http\Request), Object(Closure))
#56 vendor/barryvdh/laravel-debugbar/src/Middleware/InjectDebugbar.php(66): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#57 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Barryvdh\Debugbar\Middleware\InjectDebugbar->handle(Object(Illuminate\Http\Request), Object(Closure))
#58 vendor/fideloper/proxy/src/TrustProxies.php(57): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#59 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Fideloper\Proxy\TrustProxies->handle(Object(Illuminate\Http\Request), Object(Closure))
#60 vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#61 vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle(Object(Illuminate\Http\Request), Object(Closure))
#62 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull->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/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle(Object(Illuminate\Http\Request), Object(Closure))
#65 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\TrimStrings->handle(Object(Illuminate\Http\Request), Object(Closure))
#66 vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#67 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\ValidatePostSize->handle(Object(Illuminate\Http\Request), Object(Closure))
#68 vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#69 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance->handle(Object(Illuminate\Http\Request), Object(Closure))
#70 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#71 vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(142): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#72 vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(111): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter(Object(Illuminate\Http\Request))
#73 public/index.php(53): Illuminate\Foundation\Http\Kernel->handle(Object(Illuminate\Http\Request))
#74 server.php(21): require_once('...')
#75 {main}

I had thought I had found some records which did not cause this crash, however, I've now spotted that the error only appears when the relation shows the last page of results, so it appears all the time for records that have less than 5 related records, but not until you page to the last set if there are more than that. I feel this is a valuable clue!

I've been looking at the changelog, but I can't spot what might have affected this.

crynobone commented 2 years ago

Can you describe/explain regarding "I have some reciprocal BelongsToMany model relations (with a custom model for the join) that are set up like this:"

We already have dusk tests setup with similar structure without any issue and I don't believe the example above is enough to understand the issue.

Can you submit a full reproducing repository similar to https://github.com/nova-issues

crynobone commented 2 years ago
#0 vendor/laravel/nova/src/ResolvesFields.php(962): Laravel\Nova\Resource->pivotFieldsFor(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest), 'scans')
#1 vendor/laravel/framework/src/Illuminate/Collections/Traits/EnumeratesValues.php(482): Laravel\Nova\Resource->Laravel\Nova\{closure}(Array, true)
#2 vendor/laravel/nova/src/ResolvesFields.php(119): Illuminate\Support\Collection->when(true, Object(Closure))
#3 vendor/laravel/nova/src/ResolvesFields.php(150): Laravel\Nova\Resource->peekableFieldsCollection(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#4 vendor/laravel/nova/src/Fields/Peekable.php(85): Laravel\Nova\Resource->peekableFieldsCount(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#5 vendor/laravel/nova/src/Fields/BelongsTo.php(533): Laravel\Nova\Fields\BelongsTo->hasFieldsToPeekAt(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#6 vendor/laravel/framework/src/Illuminate/Support/helpers.php(377): Laravel\Nova\Fields\BelongsTo->Laravel\Nova\Fields\{closure}(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#7 vendor/laravel/nova/src/Fields/BelongsTo.php(542): with(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest), Object(Closure))
#8 [internal function]: Laravel\Nova\Fields\BelongsTo->jsonSerialize()

I don't understand how using BelongsToMany ends up with BelongsTo. Did you setup the fields correctly?

korridor commented 2 years ago

We have a similar error with a "MorphToMany" relation since the update to 4.6.1. (but were not on 4.6 before so it may be that the problem came with 4.6)

crynobone commented 2 years ago

@korridor can you submit reproducing code?

korridor commented 2 years ago

I just tested it again and the problem started with version 4.16.0. With 4.15.2 this error disappears. We have two models (names changed) SomeModel and OtherModel that are connected via a polymorph many-to-many relation to a model GeneralModel.

// General Model

public function someModels(): MorphToMany|SomeModel
{
    return $this->morphedByMany(SomeModel::class, 'fieldable', 'custom_table_name');
}

public function otherModels(): MorphToMany|OtherModel
{
    return $this->morphedByMany(OtherModel::class, 'fieldable', 'custom_table_name');
}
// Fields in General Model Nova Resource

MorphedByMany::make('Used By Some Models', 'someModels', SomeModel::class),
MorphedByMany::make('Used By Other Models', 'otherModels', OtherModel::class),
// Other Model

public function generalModels(): MorphToMany|GeneralModel
{
    return $this->morphToMany(
        GeneralModel::class,
        'fieldable',
        'custom_table_name',
    );
}
// Fields in Other Model Nova Resource

MorphToMany::make('General Models', 'generalModels', GeneralModel::class),

The SomeModel model and Nova resource look basically the same and the error happens for both of them.

The error happens if we go to the detail page of a GeneralModel in the request that loads the relations for SomeModel and OtherModels.

image
{
    "message": "Call to a member function settingsFields() on null",
    "exception": "Error",
    "file": "/var/www/html/vendor/laravel/nova/src/ResolvesFields.php",
    "line": 803
}
Synchro commented 2 years ago

I expect that is because it's using a custom pivot model which contains a pair of BelongsTo relations:

class ProductScan extends Pivot
{
    public $timestamps = false;

    protected $fillable = [
        'scan_id',
        'product_id',
        'is_carrier',
        'orderable_id',
    ];

    protected $casts = [
        'is_carrier' => 'boolean',
    ];

    public function scan(): BelongsTo
    {
        return $this->belongsTo(
            Scan::class
        );
    }

    public function product(): BelongsTo
    {
        return $this->belongsTo(
            Product::class
        );
    }
}

Looking at the docs, these manual relations may not be necessary any more, but regardless, they work fine in 4.15.

crynobone commented 2 years ago

@korridor can you confirm it's related to having BelongsTo/MorphTo under MorphToMany pivot model? I don't see you're having any using() or indication of that.

korridor commented 2 years ago

@crynobone We are not using custom pivot models for the relationships that are causing the problem.

juse-less commented 2 years ago

It's taken a bit of time writing the below, so there are newer messages above now. I'll still post this, in case it's of help.


I have a larger, very custom Nova and Laravel project, and isn't able to reproduce this either. I also explicitly tested the Boolean field, as that was given in the example. I've tested in both 4.15.2, and 4.16.1.

So it's also hard to help out without more details (like reproducing repo), as well.

FWIW, though. Things I've noticed with fields(), separating fields by request type (either in fields(), or by fieldsFor*()) I've noticed that Nova sometimes pass around `null` in place a resource (like a relationship), and sometimes an empty Model. My experience is that this varies depending on which type of request (index, detail, etc), and what it is that Nova wants to do (grab filters from fields, or so). This can also vary if the resource is loaded as a relationship, if I recall correctly. It doesn't always make sense to run database queries to fetch relationship(s), or the resource itself, so it's understandable. The primary reason I bring this up is because the actual line it fails on (`\Laravel\Nova\ResolvesFields#803`), tries to call ```php // If it fails because it tries to call it on null, then `resource` is null. $this->resource->{$field->manyToManyRelationship}(); ``` So if you're using `fieldsFor*()`, it might be possible you're hitting that. Granted, this is also true for `fields()`, in that it can vary what you have accessible. The most simple demonstration I can do of this is the resource itself for a detail page. This is an exact copy-paste of some things I have to do. ```php public function fieldsForDetail(): array { // The name is non-nullable in the resource, Model, and the table. // However, dumping `$this->resource` in Ray, shows the Model is empty (no attributes). $taskName = $this->name?->toString() ?? ''; return [ Tabs::make(\__('Task - :name', ['name' => $taskName]), [ ]), ]; } ``` In terms of `BelongsTo`, that Mior noticed, I tested that as well. I noticed that if you have the `BelongsTo` on the pivot table/Model, Nova will still attempt to grab it from the related resource, and not the pivot Model. ```php // Resource for \App\Models\User /** * For BelongsToMany fields to be visible, they have to be returned in the index request. */ public function fieldsForIndex(): array { // The pivot Model used is Membership, passed in the Team and User Models `BelongsToMany::using()`. BelongsToMany::make(\__('Teams'), attribute: 'teams', resource: \App\Models\Team::class) ->fields(fn (): array => [ // Comes from the pivot table/Model. I also explicitly tried Boolean through the project I work on, as that was given as example. Text::make(\__('Notes', attribute: 'notes'), // Note - this is a HasOneThrough, but a slight hack is used to invert it to link the Team owner (Team -> User) on the index row. // This will try to call `User::teamOwner()`, instead of `Membership::teamOwner()` (pivot Model). BelongsTo::make(\__('Owner'), attribute: 'teamOwner', resource: \App\Models\User::class), // None of these makes sense to show here, but to test out `BelongsTo` directly. // This will try to call `User::member()`, instead of `Membership::member()`. BelongsTo::make(\__('Member'), attribute: 'member', resource: \App\Models\User::class), // This will try to call `User::team()`, instead of `Membership::team()`. BelongsTo::make(\__('Team'), attribute: 'team', resource: \App\Models\Team::class), ]), } ```
Synchro commented 2 years ago

I tried removing the BelongsTo methods in my pivot model, and things stayed working in 4.15, so it seems they are indeed unnecessary. Curiously, I'm finding the relation in Nova 4.16 breaks in one direction but not the other, so scan->products fails, but the corresponding product->scans works. All the fields involved are using default conventions – scan_id, product_id, etc.

Notably, the stack trace still mentions BelongsTo even after removing those manual relations from my pivot model, suggesting it does the same thing internally.

Synchro commented 2 years ago

Eliminating more things – removing the pivot fields from the Nova resources doesn't change anything.

vesper8 commented 2 years ago

I'm having lots of issues with 4.16.1 related to BelongsTo. It seems to cause issues when a row has a BelongsTo that is null. Instead of aborting loading the relation, it appears to try and load it anyway even though it's null. I suspect it's related to the new peeking behaviour but I tried to disable that with noPeeking() and it doesn't seem help.

Edit: Reverting back to 4.15.2 makes all errors go away.

crynobone commented 2 years ago

@Synchro can you share the full error log after removing pivot fields?

Synchro commented 2 years ago

This is with no BelongsTo relations in the pivot model. and no pivot fields in the resources:

[2022-10-18 13:55:21] local.ERROR: Call to a member function scans() on null {"userId":1,"exception":"[object] (Error(code: 0): Call to a member function scans() on null at vendor/laravel/nova/src/ResolvesFields.php:803)
[stacktrace]
#0 vendor/laravel/nova/src/ResolvesFields.php(962): Laravel\Nova\Resource->pivotFieldsFor(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest), 'scans')
#1 vendor/laravel/framework/src/Illuminate/Collections/Traits/EnumeratesValues.php(482): Laravel\Nova\Resource->Laravel\Nova\{closure}(Array, true)
#2 vendor/laravel/nova/src/ResolvesFields.php(119): Illuminate\Support\Collection->when(true, Object(Closure))
#3 vendor/laravel/nova/src/ResolvesFields.php(150): Laravel\Nova\Resource->peekableFieldsCollection(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#4 vendor/laravel/nova/src/Fields/Peekable.php(85): Laravel\Nova\Resource->peekableFieldsCount(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#5 vendor/laravel/nova/src/Fields/BelongsTo.php(533): Laravel\Nova\Fields\BelongsTo->hasFieldsToPeekAt(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#6 vendor/laravel/framework/src/Illuminate/Support/helpers.php(377): Laravel\Nova\Fields\BelongsTo->Laravel\Nova\Fields\{closure}(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#7 vendor/laravel/nova/src/Fields/BelongsTo.php(542): with(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest), Object(Closure))
#8 [internal function]: Laravel\Nova\Fields\BelongsTo->jsonSerialize()
#9 vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(87): json_encode(Array, 0)
#10 vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\Http\JsonResponse->setData(Array)
#11 vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(32): Symfony\Component\HttpFoundation\JsonResponse->__construct(Array, 200, Array, false)
#12 vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(99): Illuminate\Http\JsonResponse->__construct(Array, 200, Array, 0)
#13 vendor/laravel/nova/src/Http/Resources/Resource.php(41): Illuminate\Routing\ResponseFactory->json(Array)
#14 vendor/laravel/nova/src/Http/Controllers/ResourceIndexController.php(19): Laravel\Nova\Http\Resources\Resource->toResponse(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest))
#15 vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): Laravel\Nova\Http\Controllers\ResourceIndexController->__invoke(Object(Laravel\Nova\Http\Requests\ResourceIndexRequest), 'products')
#16 vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): Illuminate\Routing\Controller->callAction('__invoke', Array)
#17 vendor/laravel/framework/src/Illuminate/Routing/Route.php(262): Illuminate\Routing\ControllerDispatcher->dispatch(Object(Illuminate\Routing\Route), Object(Laravel\Nova\Http\Controllers\ResourceIndexController), '__invoke')
#18 vendor/laravel/framework/src/Illuminate/Routing/Route.php(205): Illuminate\Routing\Route->runController()
#19 vendor/laravel/framework/src/Illuminate/Routing/Router.php(721): Illuminate\Routing\Route->run()
#20 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\Routing\Router->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#21 vendor/laravel/nova/src/Http/Middleware/Authorize.php(18): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#22 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel\Nova\Http\Middleware\Authorize->handle(Object(Illuminate\Http\Request), Object(Closure))
#23 vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(44): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#24 vendor/laravel/nova/src/Http/Middleware/Authenticate.php(31): Illuminate\Auth\Middleware\Authenticate->handle(Object(Illuminate\Http\Request), Object(Closure), 'web')
#25 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel\Nova\Http\Middleware\Authenticate->handle(Object(Illuminate\Http\Request), Object(Closure))
#26 vendor/laravel/nova/src/Http/Middleware/BootTools.php(20): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#27 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel\Nova\Http\Middleware\BootTools->handle(Object(Illuminate\Http\Request), Object(Closure))
#28 vendor/laravel/nova/src/Http/Middleware/DispatchServingNovaEvent.php(24): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#29 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel\Nova\Http\Middleware\DispatchServingNovaEvent->handle(Object(Illuminate\Http\Request), Object(Closure))
#30 vendor/inertiajs/inertia-laravel/src/Middleware.php(92): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#31 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Inertia\Middleware->handle(Object(Illuminate\Http\Request), Object(Closure))
#32 vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#33 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Routing\Middleware\SubstituteBindings->handle(Object(Illuminate\Http\Request), Object(Closure))
#34 vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(78): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#35 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\VerifyCsrfToken->handle(Object(Illuminate\Http\Request), Object(Closure))
#36 vendor/laravel/framework/src/Illuminate/Session/Middleware/AuthenticateSession.php(58): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#37 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Session\Middleware\AuthenticateSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#38 vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#39 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\View\Middleware\ShareErrorsFromSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#40 vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(121): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#41 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))
#42 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Session\Middleware\StartSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#43 vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#44 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle(Object(Illuminate\Http\Request), Object(Closure))
#45 vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(67): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#46 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Cookie\Middleware\EncryptCookies->handle(Object(Illuminate\Http\Request), Object(Closure))
#47 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#48 vendor/laravel/framework/src/Illuminate/Routing/Router.php(723): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#49 vendor/laravel/framework/src/Illuminate/Routing/Router.php(698): Illuminate\Routing\Router->runRouteWithinStack(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request))
#50 vendor/laravel/framework/src/Illuminate/Routing/Router.php(662): Illuminate\Routing\Router->runRoute(Object(Illuminate\Http\Request), Object(Illuminate\Routing\Route))
#51 vendor/laravel/framework/src/Illuminate/Routing/Router.php(651): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
#52 vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(167): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#53 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}(Object(Illuminate\Http\Request))
#54 vendor/laravel/nova/src/Http/Middleware/ServeNova.php(23): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#55 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel\Nova\Http\Middleware\ServeNova->handle(Object(Illuminate\Http\Request), Object(Closure))
#56 vendor/barryvdh/laravel-debugbar/src/Middleware/InjectDebugbar.php(66): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#57 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Barryvdh\Debugbar\Middleware\InjectDebugbar->handle(Object(Illuminate\Http\Request), Object(Closure))
#58 vendor/fideloper/proxy/src/TrustProxies.php(57): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#59 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Fideloper\Proxy\TrustProxies->handle(Object(Illuminate\Http\Request), Object(Closure))
#60 vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#61 vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle(Object(Illuminate\Http\Request), Object(Closure))
#62 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull->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/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle(Object(Illuminate\Http\Request), Object(Closure))
#65 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\TrimStrings->handle(Object(Illuminate\Http\Request), Object(Closure))
#66 vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#67 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\ValidatePostSize->handle(Object(Illuminate\Http\Request), Object(Closure))
#68 vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#69 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance->handle(Object(Illuminate\Http\Request), Object(Closure))
#70 vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#71 vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(142): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#72 vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(111): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter(Object(Illuminate\Http\Request))
#73 public/index.php(53): Illuminate\Foundation\Http\Kernel->handle(Object(Illuminate\Http\Request))
#74 server.php(21): require_once('...')
#75 {main}
"} 
crynobone commented 2 years ago

If the BelongsToMany field no longer has fields(), it is impossible to reach the error line 803 on ResolvesFields.

Synchro commented 2 years ago

It may be a relation on the same model elsewhere in my schema, however, since all the calls in the stack are in vendor/, I can't tell what it's tripping up on.

mstaack commented 2 years ago

also have similiar issues with null values since 1.16 like @juse-less

crynobone commented 2 years ago

@Synchro in your app, does/can Product belongs to another Product?

Synchro commented 2 years ago

Aha! Yes – products can act as containers for other products. I commented out a self-referencing BelongsTo field in the Product Nova resource, and the error goes away, so I think you're onto something there.

sanderbaas commented 2 years ago

I have the same problem with a resource (1) that has a BelongsTo relationship to a resource (2) with a BelongsToMany relationship. When resource 1 is used with a HasMany relationship on yet another resource (0), I get the same error as the op.

Resource 0 -> hasMany -> Resource 1 -> belongsTo -> Resource 2 -> BelongsToMany -> Resource 3

I suspect it has something to do with determining if there are peekable fields for resource 2.

I solved it for now by defining a fieldsForPeeking method on resource 2, where I do not include any BelongsToMany fields.

ss-koshala commented 2 years ago

Hi, I'm getting same kind error with 'HasMany' and 'BelongsToMany' fields, strange thing is not always get the errors some times get the errors like this Screenshot (156)

and this errors getting only on view mode

I'm using "laravel/nova": "4.15.2", and "laravel/framework": "^8.75",

here how I used it

        `HasMany::make('Members'),
        BelongsToMany::make('events')`

        and

        `public function members()
        {
            return $this->hasMany(Member::class);
        }

       public function events() : BelongsToMany
       {
         return $this->belongsToMany(
          Event::class,
          'events_segments'
       );
      }`
ss-koshala commented 2 years ago

Hi, I'm getting same kind error with 'HasMany' and 'BelongsToMany' fields, strange thing is not always get the errors some times get the errors like this Screenshot (156)

and this errors getting only on view mode

I'm using "laravel/nova": "4.15.2", and "laravel/framework": "^8.75",

here how I used it

        `HasMany::make('Members'),
        BelongsToMany::make('events')`

        and

        `public function members()
        {
            return $this->hasMany(Member::class);
        }

       public function events() : BelongsToMany
       {
         return $this->belongsToMany(
          Event::class,
          'events_segments'
       );
      }`

Looks this is happened me because of some times env file not reading, so APP_KEY was empty and getting error, so db connection not there and got the error, I guess. after set the 'key' => env('APP_KEY','base64:my_app_key') in app.php does not get the errors with has many and other relation fields.

ss-koshala commented 2 years ago

Hi, I'm getting same kind error with 'HasMany' and 'BelongsToMany' fields, strange thing is not always get the errors some times get the errors like this Screenshot (156) and this errors getting only on view mode I'm using "laravel/nova": "4.15.2", and "laravel/framework": "^8.75", here how I used it

        `HasMany::make('Members'),
        BelongsToMany::make('events')`

        and

        `public function members()
        {
            return $this->hasMany(Member::class);
        }

       public function events() : BelongsToMany
       {
         return $this->belongsToMany(
          Event::class,
          'events_segments'
       );
      }`

Looks this is happened me because of some times env file not reading, so APP_KEY was empty and getting error, so db connection not there and got the error, I guess. after set the 'key' => env('APP_KEY','base64:my_app_key') in app.php does not get the errors with has many and other relation fields.

sad story, error still there

Screenshot (157)

github-actions[bot] commented 2 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.