From 2a4756abff1e77e35e5c3c56c8d33e9676a6c5ab Mon Sep 17 00:00:00 2001 From: Valerio Cervo Date: Wed, 13 Sep 2017 17:34:48 +0200 Subject: [PATCH] Added actions caching --- .gitignore | 3 +- config/hermes.php | 4 +- src/Commands/ActionCacheCommand.php | 126 ++++++++++++++++++ src/Commands/ActionClearCommand.php | 54 ++++++++ src/Commands/stubs/actions.stub | 16 +++ src/Core/Application.php | 26 +++- src/Core/Contracts/Console/Kernel.php | 6 - src/Core/Contracts/Routing/Router.php | 74 ++++++++++ src/Core/Routing/ActionCollection.php | 2 +- src/Core/Routing/ActionRouter.php | 3 +- src/Core/helpers.php | 4 +- src/Ink/Action.php | 19 ++- src/Ink/Factory.php | 24 +++- src/Providers/ActionRouterServiceProvider.php | 84 ++++++++++++ .../ConsoleSupportServiceProvider.php | 4 + src/Providers/ContextServiceProvider.php | 2 - src/Providers/CredentialsServiceProvider.php | 2 +- 17 files changed, 432 insertions(+), 21 deletions(-) create mode 100644 src/Commands/ActionCacheCommand.php create mode 100644 src/Commands/ActionClearCommand.php create mode 100644 src/Commands/stubs/actions.stub create mode 100644 src/Core/Contracts/Routing/Router.php diff --git a/.gitignore b/.gitignore index a3dc1bd..4335a72 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ test.* server lang cache -bootstrap \ No newline at end of file +bootstrap +routes \ No newline at end of file diff --git a/config/hermes.php b/config/hermes.php index a04f86c..5dc24a7 100644 --- a/config/hermes.php +++ b/config/hermes.php @@ -46,9 +46,9 @@ \Illuminate\Cache\CacheServiceProvider::class, \Hermes\Providers\ContextServiceProvider::class, \Hermes\Providers\CredentialsServiceProvider::class, - \Hermes\Providers\ActionRouterServiceProvider::class, \Hermes\Providers\HttpBodyParserServiceProvider::class, - \Hermes\Providers\ConsoleSupportServiceProvider::class + \Hermes\Providers\ConsoleSupportServiceProvider::class, + \Hermes\Test\ActionServiceProvider::class ] diff --git a/src/Commands/ActionCacheCommand.php b/src/Commands/ActionCacheCommand.php new file mode 100644 index 0000000..2e75a33 --- /dev/null +++ b/src/Commands/ActionCacheCommand.php @@ -0,0 +1,126 @@ +files = $files; + + } + + /** + * Execute the console command. + */ + public function fire() + { + + $this->call('action:clear'); + + $actions = $this->getFreshApplicationActions(); + + if(count($actions) == 0) { + $this->error("Your application doesn't have any actions."); + return; + } + + foreach ($actions as $action) + { + + $action->prepareForSerialization(); + + } + + $this->files->put( + $this->hermes->getCachedActionsPath(), $this->buildActionCacheFile($actions) + ); + + $this->info('Actions cached successfully!'); + + } + + /** + * Boot a fresh copy of the application and get the actions. + * + * @return \Hermes\Core\Routing\ActionCollection + */ + protected function getFreshApplicationActions() + { + + return tap($this->getFreshApplication()['hermes.router']->getActions(), function($actions) { + + $actions->refreshNameLookups(); + $actions->refreshActionLookups(); + + }); + + } + + /** + * Get a fresh application instance. + * + * @return \Hermes\Core\Application + */ + protected function getFreshApplication() + { + + $app = require $this->hermes->bootstrapPath().'/app.php'; + + return tap($app, function($app) { + $app->make(Kernel::class)->bootstrap(); + }); + + } + + /** + * Build the action cache file. + * + * @param \Hermes\Core\Routing\ActionCollection $actions + * + * @return string + */ + protected function buildActionCacheFile(ActionCollection $actions) + { + + $stub = $this->files->get(__DIR__.'/stubs/actions.stub'); + + return str_replace('{{actions}}', base64_encode(serialize($actions)), $stub); + } + +} \ No newline at end of file diff --git a/src/Commands/ActionClearCommand.php b/src/Commands/ActionClearCommand.php new file mode 100644 index 0000000..9e08b03 --- /dev/null +++ b/src/Commands/ActionClearCommand.php @@ -0,0 +1,54 @@ +files = $files; + } + + /** + * Execute the console command. + * + * @return void + */ + public function fire() + { + $this->files->delete($this->hermes->getCachedActionsPath()); + + $this->info('Action cache cleared!'); + } +} diff --git a/src/Commands/stubs/actions.stub b/src/Commands/stubs/actions.stub new file mode 100644 index 0000000..39df082 --- /dev/null +++ b/src/Commands/stubs/actions.stub @@ -0,0 +1,16 @@ +setActions( + unserialize(base64_decode('{{actions}}')) +); diff --git a/src/Core/Application.php b/src/Core/Application.php index 1f2d5ee..1c11440 100644 --- a/src/Core/Application.php +++ b/src/Core/Application.php @@ -316,9 +316,7 @@ public function booted($callback) protected function fireAppCallbacks(array $callbacks) { foreach ($callbacks as $callback) { - dump($callback); call_user_func($callback, $this); - dump('CALL_OK'); } } @@ -785,4 +783,28 @@ public function isDownForMaintenance() return false; } + /** + * Determine if the application actions are cached. + * + * @return bool + */ + public function actionsAreCached() + { + + return $this['files']->exists($this->getCachedActionsPath()); + + } + + /** + * Get the path of the actions cache file + * + * @return string + */ + public function getCachedActionsPath() + { + + return $this->bootstrapPath() . '/cache/actions.php'; + + } + } \ No newline at end of file diff --git a/src/Core/Contracts/Console/Kernel.php b/src/Core/Contracts/Console/Kernel.php index ffa7a02..bf7f19b 100644 --- a/src/Core/Contracts/Console/Kernel.php +++ b/src/Core/Contracts/Console/Kernel.php @@ -1,10 +1,4 @@ parseWith; } + /** + * Prepare the action for the serialization + */ + public function prepareForSerialization() + { + + unset($this->validator, $this->context, $this->parser); + + } + + public function __wakeup() + { + $this->context = app(Context::class); + $this->validator = app(Validation::class); + $this->parser = app(Parsing::class); + } + } \ No newline at end of file diff --git a/src/Ink/Factory.php b/src/Ink/Factory.php index d1731f3..d0368e6 100644 --- a/src/Ink/Factory.php +++ b/src/Ink/Factory.php @@ -5,6 +5,7 @@ use Hermes\Core\Routing\ActionRouter; use Hermes\Ink\Contracts\Factory as FactoryContract; use Hermes\Core\Exceptions\EntityResolutionException; +use Illuminate\Support\Str; class Factory implements FactoryContract { @@ -67,8 +68,6 @@ public function fake($entity, $statusCode, array $responseBody) public function make($entity) { - $this->router->getActions()->refreshNameLookups(); - if(!$this->router->getActions()->hasNamedAction($entity)) { throw new EntityResolutionException($entity); } @@ -77,4 +76,25 @@ public function make($entity) } + /** + * Dynamically instantiate entities from factory + * + * @param string $method + * @param array $parameters + * + * @return mixed + */ + public function __call($method, $parameters) + { + + $snakedMethod = Str::snake($method, '.'); + if($this->router->getActions()->hasNamedAction($snakedMethod)) + { + return $this->make($snakedMethod); + } + + throw new \BadMethodCallException("Method [$method] does not exist in class " . self::class); + + } + } \ No newline at end of file diff --git a/src/Providers/ActionRouterServiceProvider.php b/src/Providers/ActionRouterServiceProvider.php index 13a2b8d..c302a70 100644 --- a/src/Providers/ActionRouterServiceProvider.php +++ b/src/Providers/ActionRouterServiceProvider.php @@ -5,10 +5,75 @@ use Hermes\Core\Routing\ActionRouter; use Illuminate\Support\ServiceProvider; +use Hermes\Core\Contracts\Routing\Router; class ActionRouterServiceProvider extends ServiceProvider { + /** + * Load the provider in a deferred manner + * + * @var bool + */ + protected $defer = true; + + + /** + * The controller namespace for the application. + * + * @var string|null + */ + protected $namespace; + + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot() + { + + if($this->app->actionsAreCached()) { + $this->loadCachedActions(); + } else { + $this->loadActions(); + + $this->app->booted(function() { + $this->app['hermes.router']->getActions()->refreshNameLookups(); + $this->app['hermes.router']->getActions()->refreshActionLookups(); + }); + } + + } + + /** + * Load the cached actions for the application. + * + * @return void + */ + protected function loadCachedActions() + { + + $this->app->booted(function() { + require $this->app->getCachedActionsPath(); + }); + + } + + /** + * Load the cached actions for the application. + * + * @return void + */ + protected function loadActions() + { + + if(method_exists($this, 'map')) { + $this->app->call([$this, 'map']); + } + + } + /** * Register the service provider * @@ -19,7 +84,10 @@ public function register() return new ActionRouter($app); }); + $this->app->alias('hermes.router', Router::class); + $this->registerFactory(); + } /** @@ -46,4 +114,20 @@ public function provides() return ['hermes.router', 'hermes.factory']; } + /** + * Pass dynamic methods onto the router instance. + * + * @param string $method + * @param array $parameters + * @return mixed + */ + public function __call($method, $parameters) + { + + return call_user_func_array( + [$this->app->make(Router::class), $method], $parameters + ); + + } + } \ No newline at end of file diff --git a/src/Providers/ConsoleSupportServiceProvider.php b/src/Providers/ConsoleSupportServiceProvider.php index 2488974..6126e40 100644 --- a/src/Providers/ConsoleSupportServiceProvider.php +++ b/src/Providers/ConsoleSupportServiceProvider.php @@ -3,6 +3,8 @@ namespace Hermes\Providers; +use Hermes\Commands\ActionCacheCommand; +use Hermes\Commands\ActionClearCommand; use Hermes\Core\ServiceProvider; use Hermes\Commands\ServeCommand; use Hermes\Commands\CacheClearCommand; @@ -23,6 +25,8 @@ class ConsoleSupportServiceProvider extends ServiceProvider ClearCompiledCommand::class, ConfigClearCommand::class, ConfigCacheCommand::class, + ActionCacheCommand::class, + ActionClearCommand::class, CacheClearCommand::class, TricksterCommand::class, ServeCommand::class, diff --git a/src/Providers/ContextServiceProvider.php b/src/Providers/ContextServiceProvider.php index d0aea3f..d89b7fe 100644 --- a/src/Providers/ContextServiceProvider.php +++ b/src/Providers/ContextServiceProvider.php @@ -9,8 +9,6 @@ class ContextServiceProvider extends ServiceProvider { - protected $defer = true; - /** * Registers the provider */ diff --git a/src/Providers/CredentialsServiceProvider.php b/src/Providers/CredentialsServiceProvider.php index 47895b4..4fec896 100644 --- a/src/Providers/CredentialsServiceProvider.php +++ b/src/Providers/CredentialsServiceProvider.php @@ -22,7 +22,7 @@ public function register() $mode = $app['config']['hermes.mode']; $type = $app['config']['hermes'][$mode]['credentials']['type']; - return $app['credentials']->driver($type); + return $app['hermes.credentials']->driver($type); }); }