diff --git a/README.md b/README.md index cb50e36..b6a006a 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,12 @@ Update `config/livewire.php`: 'class_namespace' => 'App', ``` +Regenerate the Livewire component auto-discovery manifest: + +```bash +php artisan livewire:discover +``` + Create a service provider, e.g. `LivewireServiceProvider`, and [register](https://laravel.com/docs/9.x/providers#registering-providers) the provider: ```php diff --git a/src/Domains/Domain.php b/src/Domains/Domain.php index 90a099d..43c5402 100644 --- a/src/Domains/Domain.php +++ b/src/Domains/Domain.php @@ -2,12 +2,11 @@ namespace Foxws\LivewireMultidomain\Domains; -abstract class Domain -{ - protected ?string $name = null; - - protected ?string $namespace = null; +use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Support\Arr; +abstract class Domain implements Arrayable +{ final public function __construct() { } @@ -19,35 +18,36 @@ public static function new(): static return $instance; } - public function name(string $name): self + public function attribute(string $key, mixed $default = null): mixed { - $this->name = $name; - - return $this; + return Arr::get($this->attributes, $key, $default); } - public function namespace(string $namespace): self + public function attributes(array|callable $attributes): self { - $this->namespace = $namespace; + if (is_callable($attributes)) { + $this->callableAttributes = $attributes; + } + + if (is_array($attributes)) { + $this->attributes = array_merge($this->attributes, $attributes); + } return $this; } - public function getName(): string + public function __get(string $key): mixed { - if ($this->name) { - return $this->name; - } - - return ''; + return $this->attribute($key); } - public function getNamespace(): string + public function __set(string $key, mixed $value): void { - if ($this->namespace) { - return $this->namespace; - } + $this->attributes[$key] = $value; + } - return ''; + public function __isset(string $key): bool + { + return isset($this->attributes[$key]); } } diff --git a/src/Domains/Domain/LivewireDomain.php b/src/Domains/Domain/LivewireDomain.php index af29505..ab04a83 100644 --- a/src/Domains/Domain/LivewireDomain.php +++ b/src/Domains/Domain/LivewireDomain.php @@ -6,4 +6,29 @@ class LivewireDomain extends Domain { + protected array $attributes = []; + + /** @var callable|null */ + protected $callableAttributes; + + public function name(string $name): self + { + $this->attributes(['name' => $name]); + + return $this; + } + + public function namespace(string $namespace): self + { + $this->attributes(['namespace' => $namespace]); + + return $this; + } + + public function toArray(): array + { + return [ + $this->attributes, + ]; + } } diff --git a/src/LivewireMultidomain.php b/src/LivewireMultidomain.php index dd12422..8da8e6c 100644 --- a/src/LivewireMultidomain.php +++ b/src/LivewireMultidomain.php @@ -16,7 +16,7 @@ public function domains(array $domains): self { $this->domains = array_merge($this->domains, $domains); - (new LivewireComponentsFinder()) + app(LivewireComponentsFinder::class) ->build($this->registeredDomains()); return $this; diff --git a/src/Support/LivewireComponentsFinder.php b/src/Support/LivewireComponentsFinder.php index 687eae0..97a42bc 100644 --- a/src/Support/LivewireComponentsFinder.php +++ b/src/Support/LivewireComponentsFinder.php @@ -2,13 +2,14 @@ namespace Foxws\LivewireMultidomain\Support; +use Exception; use Foxws\LivewireMultidomain\Domains\Domain\LivewireDomain; +use Illuminate\Contracts\Filesystem\FileNotFoundException; use Illuminate\Support\Collection; use Illuminate\Support\Facades\File; use Illuminate\Support\Str; use Livewire\Commands\ComponentParser; use Livewire\Component; -use Livewire\LivewireManager; use ReflectionClass; use Symfony\Component\Finder\SplFileInfo; @@ -16,28 +17,40 @@ class LivewireComponentsFinder { public function build(Collection $domains): void { - $manifest = $domains->flatMap( - fn (LivewireDomain $domain) => $this - ->getClassNames($domain->getNamespace()) + $manifest = collect($this->getManifest()); + + $manifest = $manifest->merge( + $domains->flatMap(fn (LivewireDomain $domain) => $this + ->getClassNames($domain->namespace) ->mapWithKeys(function ($class) use ($domain) { $alias = $this->getComponentAlias( - $domain->getNamespace(), - $domain->getName(), + $domain->namespace, + $domain->name, $class ); return [$alias => $class]; }) + ) ); - $this->register($manifest); + $this->write($manifest->toArray()); } - protected function register(Collection $manifest): void + protected function find($alias): ?array { - $manifest->each( - fn (string $class, string $alias) => app(LivewireManager::class)->component($alias, $class) - ); + $manifest = $this->getManifest(); + + return $manifest[$alias] ?? $manifest["{$alias}.index"] ?? null; + } + + protected function getManifest(): mixed + { + $manifestPath = $this->getManifestPath(); + + throw_if(! file_exists($manifestPath), FileNotFoundException::class); + + return File::getRequire($manifestPath); } protected function getNamespacePath(string $path): string @@ -59,7 +72,7 @@ protected function getComponentAlias(string $namespace, string $name, string $cl return "{$name}::".(string) str($fullName)->substr(strlen($namespace) + 1); } - return $fullName; + return "{$name}::{$fullName}"; } protected function getClassNames(string $namespace): Collection @@ -82,4 +95,25 @@ protected function getClassNames(string $namespace): Collection ! (new ReflectionClass($class))->isAbstract(); }); } + + protected function getManifestPath(): string + { + // We will generate a manifest file so we don't have to do the lookup every time. + $defaultManifestPath = app('livewire')->isRunningServerless() + ? '/tmp/storage/bootstrap/cache/livewire-components.php' + : app()->bootstrapPath('cache/livewire-components.php'); + + return config('livewire.manifest_path') ?: $defaultManifestPath; + } + + protected function write(array $manifest): void + { + $manifestPath = $this->getManifestPath(); + + if (! is_writable(dirname($manifestPath))) { + throw new Exception('The '.dirname($manifestPath).' directory must be present and writable.'); + } + + File::put($manifestPath, '