DEV Community

Cover image for Load Dynamically Livewire Components from Different Namespace
Nasrul Hazim Bin Mohamad
Nasrul Hazim Bin Mohamad

Posted on • Edited on

Load Dynamically Livewire Components from Different Namespace

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

php artisan make:provider LivewireDomainServiceProvider
Enter fullscreen mode Exit fullscreen mode

Add the following code:

<?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);
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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

Then you are done!


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

public static function getName()
{
    return 'domain.user.user-datatable';
}
Enter fullscreen mode Exit fullscreen mode

Main references for the implementation are coming from Jetstream Service Provider and how Artisan command get loaded dynamically in Laravel.


Photo by Dennis Brekke on Unsplash

Top comments (2)

Collapse
 
gehih81961 profile image
gehih81961 • Edited

I see there is already a package for this, you could be a new source for a new post.

Laravel Livewire Discover - github.com/joserick/laravel-livewire-discover

public function boot(): void
{
    // Load multiples namespace for Livewire components.
    Livewire::componentNamespace('Namespace\\Livewire', 'my-components');
    Livewire::componentNamespace('User\\Repository\\Livewire', 'new-components');
    ...
}
Enter fullscreen mode Exit fullscreen mode
<livewire:my-components-devices />
<livewire:new-components-devices-table />
Enter fullscreen mode Exit fullscreen mode
Collapse
 
virla01 profile image
AspectoX

interesting post, how can I do to modify and make it work for example: Admin / Http / livewire and Admin / resource / view / livewire
I have the laravel 8 application with App and Admin
Thanks for your help!