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

bugsysha's avatar

Then you have to do that from the BookingList component which contains for loop. Listen there for all bookings and reload (call API to fetch new list) when required.

kendrick's avatar

Wow, that is interesting.

created() { 
       window.Echo.private(`Bookings.all`) 
       .listen('BookingEvent', (e) => {
          this.booking = e.booking; 
      // API call
       });
    },

How would a simple API call look like?

bugsysha's avatar

Just use axios or fetch.

axios.get('https://site.domian/api/bookings')
    .then(response => this.bookings = response.data.data);

Note that this is just a snippet, I have no idea what are your routes and which data structure is returned.

1 like
kendrick's avatar

Ok, that is new to me. Does this have to be an API call and how would I structure the API route. Do you have any documentation references, where I could read more about it?

All bookings are on the /home route, I just tried:

created() { 
       window.Echo.private(`Bookings.all`) 
       .listen('BookingEvent', (e) => {
          this.booking = e.booking; 
          axios.get('/home')
            .then(response => this.bookings = response.data.data);
       });
    },

which returns a Timestamp expired: Given timestamp , not within 600ms.

Thank you for helping so much @bugsysha

bugsysha's avatar

You structure it like normal routes. There is an routes/api.php file to which you can add your API routes. Since you are asking these kind of questions I do not want to throw too much info in your direction so I think first thing is to get it working. Later you can worry about structure and other stuff.

kendrick's avatar

Thank you @bugsysha

But why is it so complex to push a new booking to a view, when listening to the Event at this view?

bugsysha's avatar

It is not complex. You are just trying to change something that was not supposed to be changed. Usually props should not be changed. When you figure out flow of data you will start thinking in that way and everything will feel natural from that point on.

kendrick's avatar

Ok, unterstand, but now I moved the created() method to the the BookingListComponent, and it is not working. And I have not yet created an API route, and don't know what I have to pass to that route.

Through a simple HomeController, I compact $bookings = Booking::all(); to the /home route, and pass it as a prop to the BookingListComponent. Within the BookingComponent, I could listen to the Event, but we had the mutation error.

What would the next step be? Do I e.g. need to put the /home route into an auth:api middleware, in order to make it work?

bugsysha's avatar

You do not have to pass anything to that route.

public function index() // assuming that the name of the controller method is index
{
    return Booking::all();
}

And do not pass data to BookingList component via props cause you are fetching it via API.

kendrick's avatar

Sorry @bugsysha , this is my current setup:

Route::get('/home', 'HomeController@home')->name('home'); // Where I listen for bookings 

// HomeController
public function home(){
    
    $bookings_ = Booking::all();
        $bookings = BookingResource::collection($bookings_);

return view('home.show', compact('bookings'));
}

show.blade.php (home)

<booking-list :bookings="{{$bookings->toJson()}}"></booking-list>

BookingListComponent

<template>
    <div> 
        <div v-for="booking in bookings"> 
            <Booking :booking="booking" />
        </div> 
    </div>
</template>
<script>
export default {
    props: ['bookings'],

    created() { 
       window.Echo.private(`Bookings.all`) 
       .listen('BookingEvent', (e) => {
          this.booking = e.booking; 
          axios.get('/api/bookings')
              .then(response => this.bookings = response.data.data);
       });
    },
}
</script>

BookingComponent

<template>
    <div>
        <p>{{booking.id}}</p>      
    </div>   
</template>

<script>
    export default {
        name: 'Booking'
        props: ['booking'],
        methods: {
             
        },
           
    }
</script>

web.php

Broadcast::channel('Bookings.all', function () {
    return true;
});

api.php

Route::get('api/bookings', function (Booking $booking) {
    return $booking;
});

What do I need to change?

bugsysha's avatar
bugsysha
Best Answer
Level 61

Something like this. But there is so many moving parts that I doubt it will work on first try.

// HomeController
public function home()
{
    return view('home.show');
}
<template>
    <div> 
        <div v-for="booking in bookings"> 
            <Booking :booking="booking" />
        </div> 
    </div>
</template>
<script>
export default {
    data() {
        return {
            bookings: []
        }
    },
    created() { 
       window.Echo.private(`Bookings.all`) 
       .listen('BookingEvent', (e) => {
        this.fetchBookings();
       });
    },
    
    methods: {
    fetchBookings() {
        axios.get('/api/bookings').then(response => this.bookings = response.data.data);
    }
    }
}
</script>
Route::get('bookings', function () {
    return Booking::all();
});
kendrick's avatar

So, if I understand it correctly the API route will allow us to trigger the bookings whenever we visit the home route, instead of passing the bookings through the home route?

kendrick's avatar

When you figure out flow of data you will start thinking in that way and everything will feel natural from that point on.

It makes perfect sense, now @bugsysha

After I create a Booking, it triggers the Event and shows the new booking alongside all others. When I refresh all bookings are gone. How can I show all bookings always, and then add the new one through the component and API?

bugsysha's avatar

Try following in your booking list component:

    created() { 
    if (!this.bookings.lenght) {
        this.fetchBookings();
    }

       window.Echo.private(`Bookings.all`) 
       .listen('BookingEvent', (e) => {
        this.fetchBookings();
       });
    },
kendrick's avatar

How could I adjust the output of bookings to be broadcasted only to specific users who e.g. have a eloquent relationship to groups?

If I have something like:

$groups = Auth::user()->groups; 
$bookings = optional($groups->map->bookings->reject->isEmpty()->flatten())->take(20); 

Is there a way to implement such a logic to the channel, or api route?

kendrick's avatar

Thank you for the link, very helpful @bugsysha

Your flow of thoughts is not confusing at all. What I was thinking of, is maybe in this logic more clear:

When I have a Channel like our bookings.all, where Booking::all(), will be broadcasted, whenever the create method is triggered. If I am a user, and I have friends(), how could I restructure bookings.all, to only broadcast bookings from my friends()?

It comes onTeam() from the video very near, somehow, right?

bugsysha's avatar

That sounds more like friend bookings channel than bookings all in my mind. Just verify that the booking belongs to a authenticated user or to a friend of authenticated user and that is it.

1 like
kendrick's avatar

Would then only the channel look different, and the api route stay the same?

Broadcast::channel('bookings-friends.{bookingId}', function (User $user, int $bookingId) {
    return $user->id === Booking::findOrFail($bookingId)->user_id; // here we authenticate the user right?
});

How would that look like when we check on friends()?

public function friends(){
        return $this->belongsToMany(User::class, 'friends', 'user_id', 'friend_id');
}
bugsysha's avatar

Would then only the channel look different, and the api route stay the same?

I would change the route also.

How would that look like when we check on friends()?

Something like...

$user->friends()->where('friend_id', $booking->user_id)->count();
kendrick's avatar

$user->friends()->where('friend_id', $booking->user_id)->count();

Thank you @bugsysha

Would that be a good way to start:

Broadcast::channel('bookings-friends.{bookingId}', function (User $user, int $bookingId) {
    
    $booking = Booking::findOrFail($bookingId);

    return $user->friends()->where('friend_id', $booking->user_id)->count();
});

And how would you consider changing the api route? So I could start testing the changes. If there are any problems occurring, I would transfer this maybe to another thread, because this one is already solved.

Again, thank you for still communicating, here. It helps immensely. @bugsysha

bugsysha's avatar

Do not forget the first check cause you need it.

return $user->id === Booking::findOrFail($bookingId)->user_id

And how would you consider changing the api route?

https://youtu.be/MF0jFKvS4SI

Previous

Please or to participate in this conversation.