Search code examples
laraveleloquentlaravel-excel

Laravel-Excel export relationship data


I am trying to export records to a CSV which queries a relation but my file keeps returning nothing but the headings.

I am making use of the laravel-excel package to do this.

Controller Method

public function export(Team $team)
{
    return Excel::download(new TeamMembersExport(), 'team_members.csv');
}

Team Method

public function members(){
    return User::with('games')->whereHas('games', function ($q) {
        $q->where('team_id', $this->id);
    })->get();
}

Export file

class ProviderMembersExport implements WithMapping, WithHeadings
{
    public function map($team): array
    {
        $members = $team->members()->only([
            'name',
            'team_number',
            'date_of_birth'
        ]);

        return $members->all();
    }

    public function headings(): array
    {
        return [
            'Name',
            'Team Number',
            'Date of Birth'
        ];
    }
}

Am i writing this incorrectly inside the mapping method?


Solution

  • There are several issues that stand out.

    1. You never pass $team to the export, which I assume is the goal based on the controller method.
    2. Mapping requires that data first be populated into the export instance using one of the From concerns: FromQuery, FromCollection, FromArray, FromView
    3. Mapping should return an array, as indicated in the method signature. This array should represent a single row in the export, not an entire query response.

    The good news is, this is all fixable with a few tweaks.

    Controller

    public function export(Team $team)
    {
        // pass the team model into the export
        return Excel::download(new TeamMembersExport($team), 'team_members.csv');
    }
    

    Export

    // add FromCollection concern
    class ProviderMembersExport implements FromCollection, WithMapping, WithHeadings
    {
        use Exportable;
    
        // a place to store the team dependency
        private $team;
    
        // use constructor to handle dependency injection
        public function __construct(Team $team)
        {
            $this->team = $team;
        }
    
        // set the collection of members to export
        public function collection()
        {
            return $this->team->members();
        }
    
        // map what a single member row should look like
        // this method will iterate over each collection item
        public function map($member): array
        {
            return [
                $member->name,
                $member->team_number,
                $member->date_of_birth,
            ];
        }
    
        // this is fine
        public function headings(): array
        {
            return [
                'Name',
                'Team Number',
                'Date of Birth'
            ];
        }
    }