View Your Laravel Project's Broadcast Channels with the "channel:list" Command
Tags: laravel, php, webdev
Published: 2023-03-08 11:40:21

## Introduction

When using WebSockets and broadcasting in your Laravel application, your `routes/channels.php` file can quickly become cluttered as your project grows. So it can sometimes be difficult to get a quick overview of the broadcast channels that you've registered.

I recently made a pull request ([#46248](https://github.com/laravel/framework/pull/46248)) that proposed a new `channel:list` Artisan command to the Laravel framework. The pull request was merged and you can now use the new command as of Laravel 10.2.0.

In this short article, we're going to take a quick look at what it does, its limitations, and future changes that I think could make the command more useful.

## What Are Broadcasting Channels?

If you're not already familiar with broadcasting channels, you may want to check out the [documentation for them here](https://laravel.com/docs/10.x/broadcasting#main-content). In the simplest terms, broadcasting channels are WebSockets channels that you can use to send data to your users' browsers without them needing to refresh the page. For example, if you had a chat application, you could use WebSockets to display the messages on the recipient's browser when someone sends a new message.

In Laravel, you can define private broadcasting channels. These are WebSockets channels that allow you to authorise the user so only the intended people can subscribe to them. Taking our chat application example, you'd only want recipients to be able to subscribe to the broadcasting channels of the chats they are part of. You wouldn't want to allow them to subscribe to the channels of other chats because this would mean they could view other people's messages.

Generally, there are two ways to define private channels. The first is to define the channel in the `routes/channels.php` file using a closure like so:

```php
Broadcast::channel('orders.{order}', function (User $user, Order $order) {
    return $user->id === $order->user_id;
});
```

Or, you could alternatively use a channel class that allows you to encapsulate this logic inside a class. For example, you could create a channel class like so:

```php
namespace App\Broadcasting;
 
use App\Models\Order;
use App\Models\User;
 
class OrderChannel
{ 
    /**
     * Authenticate the user's access to the channel.
     */
    public function join(User $user, Order $order): array|bool
    {
        return $user->id === $order->user_id;
    }
}
```

You could then update your `routes/channels.php` file to use the channel class:

```php
use App\Broadcasting\OrderChannel;
 
Broadcast::channel('orders.{order}', OrderChannel::class);
```

## The "channel:list" Command

Similar to how you can run `php artisan route:list` to get an overview of your application's routes, you might sometimes want to get a quick overview of your app's private broadcasting channels.

To do this, you can run the new `channel:list` Artisan command.

For example, if you have some private channels registered, the command output may look something like this:

![Channels found](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2nu4qqqnavrhrxhgg7mv.png)

If you don't have any private channels registered, the command output may look something like this:

![No channels found](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7j5ez7h0swvytcv6e20p.png)

To register the authorisation logic for broadcasting channels, you need to make sure the `App\Providers\BroadcastServiceProvider` provider is registered. By default, Laravel ships with this provider but doesn't automatically register it. To start using private channels, you need to find the line in your `config/app.php` file where this provider is mentioned and uncomment it. Without registering this provider, you won't be able to use private channels and you'll get a HTTP 404 response whenever you try to authorise and join one.

I can't tell you how many times I've started a new project, added my first private channel, and then sat there scratching my head when I get a 404 trying to join a private channel. On almost every project I've worked on, I've always forgotten to uncomment the line in the config file and register the provider.

To help me out with this, I added another addition to the `channel:list` command. If the `App\Providers\BroadcastServiceProvider` isn't registered, it will throw a warning. This will help me in the future!

If you run the command without the provider registered, the command output may look something like this:

![No channels found and provider not registered](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e05qby3kaxghnrbrwufv.png)

## Limitations

The most obvious limitation that I'm aware of with this command is that it only lists the private channels. This means that any public channels being used in your application won't be displayed in the command output.

This is due to the fact that public channels aren't registered like private channels. Instead, to broadcast to a public channel, you can specify any channel name you'd like when returning a new `Illuminate\Broadcasting\Channel` class from your event's `broadcastOn` method. For example, to broadcast an event to a public channel named `public-channel-name-here`, your event class may look something like so:

```php
namespace App\Events;
 
use Illuminate\Broadcasting\Channel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
 
class ServerCreated implements ShouldBroadcast
{
    use SerializesModels;

    public function broadcastOn(): array
    {
        return [
            new Channel('public-channel-name-here'),
        ];
    }
}
```

So, to my knowledge, without scraping through the application and reading every single event class that sends broadcasts, I don't think there's an easy way to detect and list the public channels. Especially, if some of the events are using complex logic for dynamically building the channel names. However, if someone does know of an easier way to do this, I'd love to hear!

Admittedly, I've never worked on a project before that's used public channels. However, if your project does use public channels, please remember that they won't be included in the command output.

## Future Changes

I have a few potential ideas for how the `channel:list` command could be improved in the future (of course, assuming Taylor Otwell and the Laravel community would find them useful).

Similar to how the `route:list` Artisan command has several options to make it a powerful tool in your arsenal, I think some extra options could be added to the channel list command. For example, I think it would be nice to have something a `--name` option (or something similar) that allows you to filter the output to only include channels that start (or match) the option passed. For instance, you could run the following command to find channels that start with the word "user":

```text
php artisan channel:list --name=user
```

I also think it would be handy to specify in the output the arguments that the channel authorisation logic expects. For example, let's take this private channel:

```php
Broadcast::channel('orders.{order}', function (User $user, Order $order) {
    return $user->id === $order->user_id;
});
```

I think it'd be pretty nice to show in the command output that the `orders.{order}` channel expects an `Order` model to be passed to it. I think this could be helpful for getting a quick insight into the channels that have vague names and don't make it obvious what parameters they expect.

I'll likely take some time in the near future to explore these ideas a bit further and make some pull requests to propose them. It's possible they may not be needed (or wanted), so they might get rejected, but it's worth a shot!

Are there any changes that you think would be useful?

## Conclusion

Hopefully, this post should have given you a quick insight into the new `channel:list` command and how you can use it in your own projects.

If you enjoyed reading this post, I'd love to hear about it. Likewise, if you have any feedback to improve the future ones, I'd also love to hear that too.

You might also be interested in checking out my 220+ page ebook "[Battle Ready Laravel](https://battle-ready-laravel.com)" which covers similar topics in more depth.

If you're interested in getting updated each time I publish a new post, feel free to [sign up for my newsletter](https://ashallendesign.co.uk/blog).

Keep on building awesome stuff! 🚀