diff --git a/changelog.md b/changelog.md index 67e38df..d87ba83 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [1.2.0] + +### Added +- Autowiring can now be cached (and cleared) with console commands + ## [1.1.0] ### Added diff --git a/composer.json b/composer.json index 4bd80f5..968de7f 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ "php": "8.0.*||8.1.*", "ergebnis/classy": "^1.3", "illuminate/support": "~8.0||~9.0", + "illuminate/console": "~8.0||~9.0", "webmozart/assert": "^1.10" }, "require-dev": { diff --git a/infection.json b/infection.json index 3a43c71..774e28b 100644 --- a/infection.json +++ b/infection.json @@ -5,7 +5,8 @@ "src" ], "excludes": [ - "AutowireServiceProvider.php" + "AutowireServiceProvider.php", + "Console/" ] }, "logs": { diff --git a/readme.md b/readme.md index d650935..6d1a730 100644 --- a/readme.md +++ b/readme.md @@ -106,6 +106,12 @@ The notations of config and service definitions is the same as used in Symfony. #[Configure(['$message' => '%app.message%', '$logger' => '@Psr\Log\LoggerInterface'])] ``` +### Caching + +The autowiring and configuration can be cached with the command `php artisan autowire:cache`. +In a similar fashion it can be cleared with `php artisan autowire:clear`. +Keep in mind that caching means that it won't crawl all the classes and changes to the annotations will not be loaded. + ## Configuration The package's configuration can be found in `config/autowire.php`. diff --git a/src/AutowireServiceProvider.php b/src/AutowireServiceProvider.php index 84bc2ac..9acf647 100644 --- a/src/AutowireServiceProvider.php +++ b/src/AutowireServiceProvider.php @@ -4,7 +4,13 @@ namespace JeroenG\Autowire; +use Illuminate\Support\Facades\App; +use Illuminate\Support\Facades\File; use Illuminate\Support\ServiceProvider; +use JeroenG\Autowire\Console\AutowireCacheCommand; +use JeroenG\Autowire\Console\AutowireClearCommand; +use JsonException; +use Illuminate\Contracts\Filesystem\FileNotFoundException; class AutowireServiceProvider extends ServiceProvider { @@ -19,44 +25,82 @@ public function register(): void { $this->mergeConfigFrom(__DIR__.'/../config/autowire.php', 'autowire'); + try { + $file = File::get(App::bootstrapPath('cache/autowire.json')); + $cache = json_decode($file, true, 512, JSON_THROW_ON_ERROR); + $this->loadFromCache($cache); + } catch (FileNotFoundException | JsonException) { + $this->crawlAndLoad(); + } + } + + protected function bootForConsole(): void + { + $this->publishes([ + __DIR__.'/../config/autowire.php' => config_path('autowire.php'), + ], 'autowire.config'); + + $this->commands([ + AutowireCacheCommand::class, + AutowireClearCommand::class, + ]); + } + + private function loadFromCache(array $cache): void + { + $autowireCache = $cache['autowire'] ?? []; + $configureCache = $cache['configure'] ?? []; + + foreach ($autowireCache as $interface => $implementation) { + $this->app->bindIf($interface, $implementation); + } + + foreach ($configureCache as $implementation => $details) { + $definition = new ConfigurationValue( + need: $details['need'], + give: $details['give'], + type: $details['type'], + ); + + $this->define($implementation, $definition); + } + } + + private function crawlAndLoad(): void + { $crawler = Crawler::in(config('autowire.directories')); $electrician = new Electrician($crawler); - $autowires = $crawler->filter(fn(string $name) => $electrician->canAutowire($name))->classNames(); + $wires = $crawler->filter(fn(string $name) => $electrician->canAutowire($name))->classNames(); $configures = $crawler->filter(fn(string $name) => $electrician->canConfigure($name))->classNames(); + foreach ($wires as $interface) { + $wire = $electrician->connect($interface); + $this->app->bindIf($wire->interface, $wire->implementation); + } + foreach ($configures as $implementation) { $configuration = $electrician->configure($implementation); foreach ($configuration->definitions as $definition) { - switch ($definition->type) { - case ConfigurationType::CONFIG: - $this->app->when($implementation)->needs($definition->need)->giveConfig($definition->give); - break; - case ConfigurationType::SERVICE: - $give = $this->app->make($definition->give); - $this->app->when($implementation)->needs($definition->need)->give($give); - break; - case ConfigurationType::UNKNOWN: - default: - $this->app->when($implementation)->needs($definition->need)->give($definition->give); - } + $this->define($implementation, $definition); } } - - foreach ($autowires as $interface) { - $wire = $electrician->connect($interface); - $this->app->bindIf($wire->interface, $wire->implementation); - } } - protected function bootForConsole(): void + private function define(string $implementation, ConfigurationValue $definition): void { - $this->publishes([ - __DIR__.'/../config/autowire.php' => config_path('autowire.php'), - ], 'autowire.config'); - - // Registering package commands. - // $this->commands([]); + switch ($definition->type) { + case ConfigurationType::CONFIG: + $this->app->when($implementation)->needs($definition->need)->giveConfig($definition->give); + break; + case ConfigurationType::SERVICE: + $give = $this->app->make($definition->give); + $this->app->when($implementation)->needs($definition->need)->give($give); + break; + case ConfigurationType::UNKNOWN: + default: + $this->app->when($implementation)->needs($definition->need)->give($definition->give); + } } } diff --git a/src/Console/AutowireCacheCommand.php b/src/Console/AutowireCacheCommand.php new file mode 100644 index 0000000..e6708a0 --- /dev/null +++ b/src/Console/AutowireCacheCommand.php @@ -0,0 +1,54 @@ +filter(fn(string $name) => $electrician->canAutowire($name))->classNames(); + $configures = $crawler->filter(fn(string $name) => $electrician->canConfigure($name))->classNames(); + $autowireCache = []; + $configureCache = []; + + foreach ($autowires as $interface) { + $wire = $electrician->connect($interface); + $autowireCache[$wire->interface] = $wire->implementation; + } + + foreach ($configures as $implementation) { + $configuration = $electrician->configure($implementation); + + foreach ($configuration->definitions as $definition) { + $configureCache[$implementation] = [ + 'type' => $definition->type, + 'need' => $definition->need, + 'give' => $definition->give, + ]; + } + } + + $cache = [ + 'autowire' => $autowireCache, + 'configure' => $configureCache, + ]; + + File::put(App::bootstrapPath('cache/autowire.json'), json_encode($cache, JSON_THROW_ON_ERROR)); + + $this->info('Autowire cache created!'); + return 0; + } +} diff --git a/src/Console/AutowireClearCommand.php b/src/Console/AutowireClearCommand.php new file mode 100644 index 0000000..b46fc1f --- /dev/null +++ b/src/Console/AutowireClearCommand.php @@ -0,0 +1,29 @@ +error('Could not clear cache.'); + return 1; + } + + $this->info('Autowire cache cleared!'); + return 0; + } +}