Load Dynamically Livewire Components from Different Namespace
Tags: laravel, livewire
Published: 2021-11-29 08:52:16

If you are familiar with Laravel Livewire, you might come across (especially you working with huge projects), how to manage the Livewire components, to be organise under their own domain.

In my case, I have a project, consider as a big one, need some organisation of each respective domain (can say that I'm using Domain Driven Development - DDD). Livewire one of its component and I don't want to use default Livewire namespace - `App\Livewire`. I want to use `App\Domain\User\Livewire`, `App\Domain\Payroll\Livewire`, etc.

But how do i dynamically register all the Livewire components under the domain?

They keyword is 

- `Livewire::component('name.of.the.component', FQCN)`
- Load recursively the domain namespace, and 
- Only load classes which is subclass of `Livewire\Component` class.

### TLDR

```bash
php artisan make:provider LivewireDomainServiceProvider
```

Add the following code:

```php
<?php

namespace App\Providers;

use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Arr;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use Livewire\Component as LivewireComponent;
use Livewire\Livewire;
use Symfony\Component\Finder\Finder;

class LivewireDomainServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        if (class_exists(Livewire::class)) {
            $this->load(app_path('Domain'));
        }
    }

    private function load($paths)
    {
        $paths = array_unique(Arr::wrap($paths));

        $paths = array_filter($paths, function ($path) {
            return is_dir($path);
        });

        if (empty($paths)) {
            return;
        }

        $namespace = 'App\Domain\\';

        foreach ((new Finder())->in($paths)->files() as $domain) {
            $component = $namespace.str_replace(
                ['/', '.php'],
                ['\\', ''],
                Str::after($domain->getRealPath(), realpath(app_path('Domain')).DIRECTORY_SEPARATOR)
            );

            if (is_subclass_of($component, LivewireComponent::class)) {
                Livewire::component($component::getName(), $component);
            }
        }
    }
}
```

Then register the service provider in `config/app.php`.

Then you are done!

<hr>

You may want to define your own Livewire domain component by explicitly define in the component class like the following:

```php
public static function getName()
{
    return 'domain.user.user-datatable';
}
```

<hr>

Main references for the implementation are coming from [Jetstream Service Provider](https://github.com/laravel/jetstream/blob/24d90e998a97636871d1d0f6a2f32cc8f954666d/src/JetstreamServiceProvider.php#L40) and how [Artisan command get loaded dynamically](https://github.com/laravel/framework/blob/78637dcc784e8c85e08490d47098cd7531dcaa81/src/Illuminate/Foundation/Console/Kernel.php#L208) in Laravel.

<hr>

Photo by <a href="https://unsplash.com/@dennnnnnis?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Dennis Brekke</a> on <a href="https://unsplash.com/s/photos/wire?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>