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

Meaulnes's avatar

How to write a route to a hasMany relationShip ?

In laravel I have these Models that describe a day event in which people participate to activities. Each event has many activities but an activity belongs only to one event. I cannot manage to write a route that allows me to get the activities of a given event.

Model Event

<?php
namespace App\Models;
use App\Models\Activity;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Event extends Model
{
    use HasFactory;
    protected $table = 'events';
    protected $fillable = [
        'label',
        'date',
        'activities',
        'cassetteOperations',
        'bankOperations'
    ];

    /**
     * Get all of the event's activities.
    */
    public function activities(): HasMany
    {
        return $this->hasMany(Activity::class);
    }
}

Model Activity

<?php
namespace App\Models;
use App\Models\Participation;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;

class Activity extends Model
{
    use HasFactory;
    protected $fillable = [
        'label',
        'event_id',
        'memberPrice',
        'otherPrice',
        'memberEntryFee',
        'otherEntryFee',
        'type',
        'participations'
    ];

    /**
     * Get the participations for the activity
     */
    public function participations(): HasMany
    {
        return $this->hasMany(Participation::class);
    }

    /**
     * Get the event associated with the activity
     */
    public function event(): HasOne
    {
        return $this->hasOne(Event::class);
    }

    /**
     * Get the persons that participates to this activity
     *
     */
    public function participants(): HasManyThrough
    {
        return $this->hasManyThrough(Person::class, Participation::class);
    }
}

In the App/Http/Api/ActivityController I have

<?php
namespace App\Http\Controllers\Api;

use App\Models\Event;
use App\Models\Activity;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Resources\ActivityResource;
use App\Http\Requests\StoreActivityRequest;

class ActivityController extends Controller
{
    public function index($event_id)
    {
        return ActivityResource::collection(Activity::where('event_id', $event_id)->orderBy('id')->get());

    }

    public function store(StoreActivityRequest $request)
    {
        Activity::create($request->validated());
        //return only activities bound to the event
        return ActivityResource::collection(Activity::where('event_id', $request->event_id)->orderBy('id')->get());
    }

}

In routes/api I have

Route::middleware(['auth:sanctum'])->get('/user', function (Request $request) {
    return $request->user();
});
Route::apiResource('person',PersonController::class)->middleware(['auth'])->middleware('App\Http\Middleware\Allowed');
Route::apiResource('event',EventController::class)->middleware(['auth'])->middleware('App\Http\Middleware\Allowed');

Route::get('activity/{event_id}',[ActivityController::class,'index'])->middleware(['auth'])->middleware('');
Route::apiResource('activity',ActivityController::class)->middleware(['auth'])->middleware('App\Http\Middleware\Allowed');

When in my vue project I target the following

async apiFetchEventActivities(event_id) {
    try {
        await axios.get('sanctum/csrf-cookie')
        this.activityErrors = []
        const { data } = await axios.get('/api/activity/' + event_id)
        this.activities = data.data

    } catch ({ response }) {
        this.activityErrors = [response.data.message, response.status]
        return ('failure')
    }
}

I get a error status 500 with "message": "Target class [] does not exist.",

Is my route (the one before last in routes/api) not correct and why ? How should I write it?

0 likes
8 replies
vincent15000's avatar
Level 63

I suggest you some modifications.

Event model => the activities aren't a field, but a relationship, so don't add this property to the fillable array

// Activity model

public function event(): HasOne
{
    return $this->belongsTo(Event::class);
}

Then to retrieve the activites belonging to an event, you just need the event id.

You can create the needed nested controller.

Route::get('events/{event}/activities', [EventActivityController::class, 'index']);

And the controller will look like this one.

public function index(Event $event)
{
	return ActivityResource::collection($event->activities);
}
Meaulnes's avatar

Merci l'ami. Bonne fin d'année.

1 like
Meaulnes's avatar

Please stay watching. It doesn't work for me at the moment.

1 like
Meaulnes's avatar

Doing this request await axios.get('events/8/activities') I get an error call to a member function first() on null. The event with id = 8 exists in the database.

1 like
Meaulnes's avatar

If I change the controller like this

  public function index( $eventId){
      $event = Event::where("id",$eventId)->get();
    //or $event= Event::find($eventId)->get();
       return ActivityResource::collection($event->activities);
}

the response is Property [activities] doesn't exist on this collection instance

1 like
vincent15000's avatar

@Meaulnes You have to change this.

$event = Event::where("id",$eventId)->get();

To this.

$event = Event::where('id', $eventId)->first();

Or better.

$event = Event::find('id', $eventId);

If you use the get() method, you retrieve a collection and not a model.

But it's better to use model binding instead.

public function index(Event $event){
       return ActivityResource::collection($event->activities);
}
Meaulnes's avatar

Thank you very much. I could manage to have it working. My trouble was coming from an inappropriate remaining activities function from previous groping in the EventController. I could even have it working with an other resource using a hasManyThrough relationship. I think I need a deeper reading of the laravel documentation. Thank you again and happy new year. Bonne année 2024

1 like

Please or to participate in this conversation.