Skip to content

Commit

Permalink
Merge pull request #2 from Jeroen-G/caching
Browse files Browse the repository at this point in the history
Add ability to cache autowiring and configurations
  • Loading branch information
Jeroen-G authored Jan 6, 2022
2 parents c4a1bee + 3f36313 commit b1a891f
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 26 deletions.
5 changes: 5 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
3 changes: 2 additions & 1 deletion infection.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"src"
],
"excludes": [
"AutowireServiceProvider.php"
"AutowireServiceProvider.php",
"Console/"
]
},
"logs": {
Expand Down
6 changes: 6 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
94 changes: 69 additions & 25 deletions src/AutowireServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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);
}
}
}
54 changes: 54 additions & 0 deletions src/Console/AutowireCacheCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php declare(strict_types=1);

namespace JeroenG\Autowire\Console;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\File;
use JeroenG\Autowire\Crawler;
use JeroenG\Autowire\Electrician;

class AutowireCacheCommand extends Command
{
protected $signature = 'autowire:cache';

protected $description = 'Cache the autowiring and configurations.';

public function handle(): int
{
$crawler = Crawler::in(config('autowire.directories'));
$electrician = new Electrician($crawler);

$autowires = $crawler->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;
}
}
29 changes: 29 additions & 0 deletions src/Console/AutowireClearCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php declare(strict_types=1);

namespace JeroenG\Autowire\Console;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\File;
use JeroenG\Autowire\Crawler;
use JeroenG\Autowire\Electrician;

class AutowireClearCommand extends Command
{
protected $signature = 'autowire:clear';

protected $description = 'Clear the cache.';

public function handle(): int
{
$deleted = File::delete(App::bootstrapPath('cache/autowire.json'));

if (!$deleted) {
$this->error('Could not clear cache.');
return 1;
}

$this->info('Autowire cache cleared!');
return 0;
}
}

0 comments on commit b1a891f

Please sign in to comment.