Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Maison012's avatar

Canot access relationships inside map collection

Want to export my data from table on excel (xls) format. But i have some model relationship there, and for now i can just ecport only one modal data.

Here is the export method

public function export(Job $jobs)
    {
        return Excel::download(new JobsExport($jobs), 'jobs.xlsx');
    }

job model

public function jobsExport(){
        return Job::with(['templates', 'teams'])->get();
    }

also export.php

class JobsExport implements FromCollection, WithMapping, WithHeadings
{
    use Exportable;
    
    private $jobs;

    public function __construct(Job $jobs)
    {
        $this->jobs = $jobs;
    }

    public function collection()
    {
        return $this->jobs->jobsExport();
    }

    public function map($jobsExport): array
    {
        return [
            $jobsExport->job_name,
            $jobsExport->templates->template_name,  //i cant access this
            $jobsExport->job_description,
            $jobsExport->job_completed,
        ];
    }

    /**
    * @return \Illuminate\Support\Collection
    */ 
    public function headings():array
    {
        return[
            'Id',
            'Created_at',
            'Updated_at' 
        ];
    } 

}

Jobtypes and teams canot exported there is my problem

0 likes
25 replies
Snapey's avatar

load the required related data in the constructor

     public function __construct(Job $jobs)
    {
        $jobs->load('templates','teams');
        $this->jobs = $jobs;
        
    }
Maison012's avatar

@Snapey i get same error message

Property [template_name] does not exist on this collection instance.

i can get the relation like this

public function map($jobsExport): array
    {
        dd($jobsExport->templates);

//but i cant get the template_name
public function map($jobsExport): array
    {
        dd($jobsExport->templates->template_name);
Sinnbeck's avatar

@Leon012 I assume that templates means that there are more than 1. So you cannot just get a property like that

here I get the first, but you could do a foreach() instead

dd($jobsExport->templates->first()->template_name);
1 like
Sinnbeck's avatar

@Leon012 Exactly. But you need them all? How do should be be added in the excel file? Just comma separated inside a cell?

dd($jobsExport->templates->pluck('template_name')->implode(', '));

Edit: Sorry didnt see @silencebringer has just answered the same :)

1 like
Maison012's avatar

@Sinnbeck It is okay now i understand the implode method. But another problem is all record are exported, and i sent just selcted record form front

Maison012's avatar

@snapey Any other method what can i use, i have tryed some method by myself but any of these does not work, Not sure why cant i call template_name inside a map function

 public function map($jobsExport): array
    {
        // dd($jobsExport->templates);
        return [
            $jobsExport->job_name,
            $jobsExport->templates->template_name,
            $jobsExport->job_description,
            $jobsExport->job_completed,
        ];
    }
SilenceBringer's avatar

@Leon012 looks like you have wrong relationship type for templates, because it returns you the collection

So, your job hasMany templates. This way you can't use it like $jobsExport->templates->template_name, it may be something like https://laravel.com/docs/9.x/collections#method-implode

$jobsExport->templates->implode('template_name', ', ')

to join all templates names in a line

1 like
Maison012's avatar

@SilenceBringer This is working perfect i can export template_name with implode method.

But there is still a problem, from the front i send only selected record from table but anyway this methos exports all records

SilenceBringer's avatar

@Leon012 because here

public function jobsExport(){
        return Job::with(['templates', 'teams'])->get();
    }

you returns all the records (not filtered). Apply required where conditions to select the records you need, like https://laravel.com/docs/9.x/queries#conditional-clauses

	public function jobsExport(){
        return Job::with(['templates', 'teams'])
			->when(request('ids'), fn ($query) => $query->whereIn('id, request('ids')))
			->get();
    }
SilenceBringer's avatar

@Leon012 it means you did filtering wrong. Please, provide me with the dump of request data

	public function jobsExport(){
		dd(request()->all());
        return Job::with(['templates', 'teams'])->get();
    }
SilenceBringer's avatar

@Leon012 which means you do not send and data for filtering. What do you expect this way? All the data is corrrect result

Maison012's avatar

@SilenceBringer i see , and i send data from front using vue js like this

watch: {
//get all selected record and pass on `/export/jobs/` route
            selected: function(){
                this.url = '/export/jobs/' + this.selected;
            }
        },

route

Route::any('export/jobs/{jobs}', [JobController::class, 'export']);
SilenceBringer's avatar

@leon012 ok, I see. dump the input

	public function jobsExport($jobs){
		dd($jobs);
        return Job::with(['templates', 'teams'])->get();
    }
Maison012's avatar

@SilenceBringer I tryed this method with $jobs and $request but i have got this error

Too few arguments to function App\Models\Job::jobsExport(), 0 passed in 
...app\Exports\JobsExport.php on line 26 and exactly 1 expected
SilenceBringer's avatar

@Leon012

public function export(Job $jobs)
    {
		dd($jobs);
        return Excel::download(new JobsExport($jobs), 'jobs.xlsx');
    }
Maison012's avatar

@SilenceBringer

App\Models\Job {#1399 ▼
  #fillable: array:6 [▶]
  #connection: "mysql"
  #table: "jobs"
  #primaryKey: "id"
  #keyType: "int"
  +incrementing: true
  #with: []
  #withCount: []
  +preventsLazyLoading: false
  #perPage: 15
  +exists: true
  +wasRecentlyCreated: false
  #escapeWhenCastingToString: false
  #attributes: array:9 [▶]
  #original: array:9 [▶]
  #changes: []
  #casts: []
  #classCastCache: []
  #attributeCastCache: []
  #dates: []
  #dateFormat: null
  #appends: []
  #dispatchesEvents: []
  #observables: []
  #relations: []
  #touches: []
  +timestamps: true
  #hidden: []
  #visible: []
  #guarded: array:1 [▶]
}

this is the result from controller

SilenceBringer's avatar

@leon012


class JobsExport implements FromCollection, WithMapping, WithHeadings
{
	// ...

    public function collection()
    {
        return $this->jobs->jobsExport($this->jobs);
    }

	// ... 
}
Maison012's avatar

@silencebringer I tryed to filter selected record like this based on laravel documentation https://laravel.com/docs/9.x/queries#conditional-clauses

public function jobsExport($jobs)
    {
Job::with( 'templates', 'teams')
        ->when($jobs, function ($query, $jobs) {
            $query->where('id', $jobs);
        })
        ->get()

and this is the result

Illuminate\Database\Eloquent\Collection {#1614 ▼
  #items: []
  #escapeWhenCastingToString: false
}
aosdev's avatar

You have to map templates too. Because you have one to many relationship.

Maison012's avatar

@aosdev i have many to many relationships. but if i try this

$job = $jobs->id;

return Job::with([ 'templates', 'teams'])
            ->when($job, function ($query, $job) {
                $query->where('id', $job);
            })
            ->get();

i get only first record i select

Maison012's avatar

@snapey Still looking to find a solution to solve my problem but any of these does not work. What am i doing wrong here.

public function jobsExport($jobs)
    {
        $job = $jobs->id;
        return Job::with( 'templates', 'teams')
            ->when($job, function ($query, $job) {
                $query->where('id', $job);
            })
            ->get();
    }

Like this i can export only one selected record, but i want to export multiple record. Then i tryed to change $query ->where('id', $job) to this

$query->whereIn('id', $jobs);

But like this i am getting error and record does not export

Please or to participate in this conversation.