laravel / nova-issues

557 stars 34 forks source link

Pivot action doesn't resolve models when using custom pivot attribute name #2790

Closed deshack closed 4 years ago

deshack commented 4 years ago

Description:

ActionRequest::mapChunk() doesn't take custom pivot attribute names into consideration. Therefore, when resolving the resources on which to apply the action, it populates a collection of null values where pivot models should be returned. This in turn resolves in a Trying to access property <pivot foreign key> on a non-object error in ActionRequest::actionableKey(), called by ActionEvent.

protected function mapChunk($chunk)
    {
        return ActionModelCollection::make($this->isPivotAction()
                    ? $chunk->map->pivot // pivot should be `participation` in our example below
                    : $chunk);
    }

Detailed steps to reproduce the issue on a fresh Nova installation:

  1. Define two models related by a many-to-many relationship with pivot data and custom pivot attribute name.

First model:

class Group extends Model {
  public function participants() {
        return $this->belongsToMany( User::class, 'group_user', 'group_id', 'user_id' )
                    ->as( 'participation' )
                    ->using( GroupParticipant::class )
                    ->withPivot( [ 'is_admin' ] )
                    ->withTimestamps();
    }
}

Second model:

class User extends Model {
   public function groups() {
        return $this->belongsToMany( Group::class, 'group_user', 'user_id', 'group_id' )
                    ->as( 'participation' )
                    ->using( GroupParticipant::class )
                    ->withPivot( [ 'is_admin' ] )
                    ->withTimestamps();
    }
}

Pivot model:

class GroupParticipant extends Pivot {
  protected $table = 'group_user';

    protected $casts = [
        'is_admin' => 'bool',
    ];
}
  1. Define Nova resources with bi-directional relationship.
class Group extends Resource {
// ...

  public function fields( Request $request ) {
    return [
      BelongsToMany::make( 'Participants', 'participants', User::class )->searchable()
                         ->fields( function () {
                             return [
                                 Boolean::make( 'Administrator', 'is_admin' ),
                             ];
                         } )
                         ->actions( function () {
                             return [
                                 new MyGroupParticipantAction()
                             ];
                         } ),
    ];
  }
// ...
}
class User extends Resource {
// ...

  public function fields( Request $request ) {
    return [
      BelongsToMany::make( 'Groups', 'groups', Group::class )->searchable()
                         ->fields( function () {
                             return [
                                 Boolean::make( 'Amministratore', 'is_admin' ),
                             ];
                         } )
                         ->actions( function () {
                             return [
                                 new MyGroupParticipantAction()
                             ];
                         } ),
    ];
  }
// ...
}

Action is omitted since it doesn't really matter.

  1. On the Group detail screen, select at least one related model and run the MyGroupParticipantAction action.
  2. An error is thrown:

Trying to get property 'group_id' of non-object {"userId":1,"exception":"[object] (ErrorException(code: 0): Trying to get property 'group_id' of non-object at /path/to/nova/src/Http/Requests/ActionRequest.php:189)

deshack commented 4 years ago

A solution could be the following:

protected function mapChunk( $chunk ) {
        return ActionModelCollection::make( $this->isPivotAction()
            ? $chunk->map->{$this->pivotRelation()->getPivotAccessor()}
            : $chunk );
    }

Given that ActionRequest::pivotRelation() returns a BelongsToMany relation.

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

benlumley commented 3 years ago

I am seeing this issue; and the suggested fix above fixes it.

Laravel 8.37.9 Nova 3.23.2 PHP 8.0.1

crynobone commented 3 years ago

Laravel Nova does come with dusk tests covering pivot action with fields on BelongsToMany relationship and it's returning green. At this point please create a full reproducing code to demonstrate the issue in case there a use case that we have yet to discover.

Evanslooten commented 1 year ago

I ran into this issue in my current project with Nova. The proposed solution did correct the issue with the action on the pivot. I'd be happy to provide whatever information you need to identify the issue.

crynobone commented 1 year ago

@Evanslooten submit new bug report using the available template.