Skip to content

Commit

Permalink
feat, refactor: application with bootstrapper (#327)
Browse files Browse the repository at this point in the history
* feat, refactor: application with bootstrapper

- add karnel register appliaction bootstrapper
- add BootProvider: to call `Application::bootProvider`
- add RegisterProvider: to call `Application::registerProvider`

* refactor: use native Application Container method

* refactor: remove booted check. register run before boot

* feat: application callbacks after and before boot
  • Loading branch information
SonyPradana authored May 20, 2024
1 parent 6d14669 commit bc2ad0e
Show file tree
Hide file tree
Showing 10 changed files with 294 additions and 10 deletions.
103 changes: 95 additions & 8 deletions src/System/Integrate/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,32 @@ final class Application extends Container
*/
private $isBooted = false;

/**
* Detect application has been bootstrapped.
*/
private bool $isBootstrapped = false;

/**
* Terminate callback register.
*
* @var callable[]
*/
private $terminateCallback = [];

/**
* Registered booting callback.
*
* @var callable[]
*/
protected array $booting_callbacks = [];

/**
* Registered booted callback.
*
* @var callable[]
*/
protected array $booted_callbacks = [];

/**
* Contructor.
*
Expand All @@ -198,10 +217,6 @@ public function __construct(string $base_path)
// register base provider
$this->register(IntegrateServiceProvider::class);

// boot provider
$this->registerProvider();
$this->bootProvider();

// register container alias
$this->registerAlias();
}
Expand Down Expand Up @@ -829,8 +844,38 @@ public function isDev()
return $this->environment() === 'dev';
}

/**
* Detect appliaction has been booted.
*/
public function isBooted(): bool
{
return $this->isBooted;
}

/**
* Detect application has been bootstrapped.
*/
public function isBootstrapped(): bool
{
return $this->isBootstrapped;
}

// core region

/**
* Bootstrapper.
*
* @param array<int, class-string> $bootstrappers
*/
public function bootstrapWith($bootstrappers): void
{
$this->isBootstrapped = true;

foreach ($bootstrappers as $bootstrapper) {
$this->make($bootstrapper)->bootstrap($this);
}
}

/**
* Boot service provider.
*
Expand All @@ -842,6 +887,8 @@ public function bootProvider()
return;
}

$this->callBootCallbacks($this->booting_callbacks);

foreach ($this->providers as $provider) {
if (in_array($provider, $this->booted_providers)) {
continue;
Expand All @@ -851,6 +898,8 @@ public function bootProvider()
$this->booted_providers[] = $provider;
}

$this->callBootCallbacks($this->booted_callbacks);

$this->isBooted = true;
}

Expand All @@ -861,10 +910,6 @@ public function bootProvider()
*/
public function registerProvider()
{
if (!$this->isBooted) {
return;
}

foreach ($this->providers as $provider) {
if (in_array($provider, $this->looded_providers)) {
continue;
Expand All @@ -876,6 +921,46 @@ public function registerProvider()
}
}

/**
* Call the registered booting callbacks.
*
* @param callable[] $bootCallBacks
*/
public function callBootCallbacks($bootCallBacks): void
{
$index = 0;

while ($index < count($bootCallBacks)) {
$this->call($bootCallBacks[$index]);

$index++;
}
}

/**
* Add booting call back, call before boot is calling.
*
* @param callable[] $callback
*/
public function bootingCallback($callback): void
{
$this->booting_callbacks[] = $callback;
}

/**
* Add booted call back, call after boot is called.
*
* @param callable[] $callback
*/
public function bootedCallback($callback): void
{
$this->booted_callbacks[] = $callback;

if ($this->isBooted()) {
$this->call($callback);
}
}

/**
* Flush or reset application (static).
*/
Expand All @@ -887,6 +972,8 @@ public function flush(): void
$this->looded_providers = [];
$this->booted_providers = [];
$this->terminateCallback = [];
$this->booting_callbacks = [];
$this->booted_callbacks = [];

parent::flush();
}
Expand Down
15 changes: 15 additions & 0 deletions src/System/Integrate/Bootstrap/BootProviders.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace System\Integrate\Bootstrap;

use System\Integrate\Application;

class BootProviders
{
public function bootstrap(Application $app): void
{
$app->bootProvider();
}
}
15 changes: 15 additions & 0 deletions src/System/Integrate/Bootstrap/RegisterProviders.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace System\Integrate\Bootstrap;

use System\Integrate\Application;

class RegisterProviders
{
public function bootstrap(Application $app): void
{
$app->registerProvider();
}
}
22 changes: 22 additions & 0 deletions src/System/Integrate/Console/Karnel.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,25 @@

use System\Console\Style\Style;
use System\Integrate\Application;
use System\Integrate\Bootstrap\BootProviders;
use System\Integrate\Bootstrap\RegisterProviders;

class Karnel
{
/**
* Application Container.
*/
protected Application $app;

/** @var int concole exit status */
protected $exit_code;

/** @var array<int, class-string> Apllication bootstrap register. */
protected array $bootstrappers = [
RegisterProviders::class,
BootProviders::class,
];

/**
* Set instance.
*/
Expand All @@ -34,6 +46,8 @@ public function handle($arguments)
$baseArgs = $arguments[1] ?? '--help';
$commands = [];

$this->bootstrap();

foreach ($this->commands() as $cmd) {
$commands = array_merge($commands, $cmd->patterns(), $cmd->cmd());

Expand Down Expand Up @@ -78,6 +92,14 @@ public function handle($arguments)
return $this->exit_code = 1;
}

/**
* Register bootstraper application.
*/
public function bootstrap(): void
{
$this->app->bootstrapWith($this->bootstrappers);
}

/**
* Return similar from given array, compare with key.
*
Expand Down
21 changes: 21 additions & 0 deletions src/System/Integrate/Http/Karnel.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
use System\Http\Request;
use System\Http\Response;
use System\Integrate\Application;
use System\Integrate\Bootstrap\BootProviders;
use System\Integrate\Bootstrap\RegisterProviders;
use System\Integrate\Exceptions\Handler;
use System\Integrate\Http\Middleware\MaintenanceMiddleware;
use System\Router\Router;

class Karnel
{
/**
* Application Container.
*/
protected Application $app;

/** @var array<int, class-string> Global middleware */
Expand All @@ -23,6 +28,12 @@ class Karnel
/** @var array<int, class-string> Middleware has register */
protected $middleware_used = [];

/** @var array<int, class-string> Apllication bootstrap register. */
protected array $bootstrappers = [
RegisterProviders::class,
BootProviders::class,
];

/**
* Set instance.
*/
Expand All @@ -43,6 +54,8 @@ public function handle(Request $request)
$this->app->set(Request::class, $request);

try {
$this->bootstrap();

$dispatcher = $this->dispatcher($request);

$pipeline = array_reduce(
Expand All @@ -62,6 +75,14 @@ public function handle(Request $request)
return $response;
}

/**
* Register bootstraper application.
*/
public function bootstrap(): void
{
$this->app->bootstrapWith($this->bootstrappers);
}

/**
* Terminate Requesr and Response.
*/
Expand Down
65 changes: 65 additions & 0 deletions tests/Integrate/ApplicationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,63 @@ public function itCanAbortApplication()
(new Application(__DIR__))->abort(500);
}

/** @test */
public function itCanBootstrapWith()
{
$app = new Application(__DIR__);

ob_start();
$app->bootstrapWith([
TestBootstrapProvider::class,
]);
$out = ob_get_clean();

$this->assertEquals($out, 'TestBootstrapProvider::bootstrap');
$this->assertTrue($app->isBootstrapped());
}

/** @test */
public function itCanAddCallBacksBeforeAndAfterBoot()
{
$app = new Application(__DIR__);

$app->bootedCallback(static function () {
echo 'booted01';
});
$app->bootedCallback(static function () {
echo 'booted02';
});
$app->bootingCallback(static function () {
echo 'booting01';
});
$app->bootingCallback(static function () {
echo 'booting02';
});

ob_start();
$app->bootProvider();
$out = ob_get_clean();

$this->assertEquals($out, 'booting01booting02booted01booted02');
$this->assertTrue($app->isBooted());
}

public function itCanAddCallImediatllyIfApplicationAlredyBooted()
{
$app = new Application(__DIR__);

$app->bootProvider();

ob_start();
$app->bootedCallback(static function () {
echo 'imediatly call';
});
$out = ob_get_clean();

$this->assertTrue($app->isBooted());
$this->assertEquals($out, 'imediatly call');
}

/** @test */
public function itCanCallDeprecatedMethod()
{
Expand Down Expand Up @@ -238,3 +295,11 @@ private function defaultConfigs()
];
}
}

class TestBootstrapProvider
{
public function bootstrap(Application $app): void
{
echo __CLASS__ . '::' . __FUNCTION__;
}
}
Loading

0 comments on commit bc2ad0e

Please sign in to comment.