本文へ移動
BlackOps1.xは試験的なバージョンです。Production Readyは2.xを予定しています。Releases
BlackOps
Esc
navigateopen⌘Jpreview
このページの内容

Application Bootstrap

BuilderとProcess bootstrapの署名、登録順、HTTP/Consoleの失敗境界を引く。

Installed ApplicationはApplication Rootを起点にPublic Application BuilderからHTTPとConsoleの共通Configuration Snapshotを作ります。

use BlackOps\Application\Application;

$application = Application::configure(dirname(__DIR__))
    ->withEnvironmentFile()
    ->withConfiguration()
    ->create();

configure()は存在するApplication Rootを絶対Pathへ正規化します。不正なRoot、Environment、Config、RegistrationはApplicationBootstrapExceptionで拒否されます。

EnvironmentとConfiguration

既定のInstalled ApplicationはwithEnvironmentFile()でProcess EnvironmentとOptional .envを一度だけSnapshotします。Process Environmentが.envより優先され、.envがない場合も起動できます。Testや外部Secret Loaderなど、解決済みの値を渡す場合だけwithEnvironment(array)を使います。Dotenv実装はFrameworkが所有し、ApplicationはVendor Runtime Classを直接Importしません。

withConfiguration()は既定で<application-root>/configを読みます。認識する設定ファイルはConfigurationの一覧(app.phpdatabase.phpoperations.phpexecution.phpjournal.phpmiddleware.phpretention.phpauth.phplogging.phpdiagnostics.phpfrontend.php)と一致します。存在しない既定Directoryは空Configとして扱い、一覧にないファイルは読みません。

Configは呼出時に一度だけ読み、create()後のFile変更を自動反映しません。各設定のShapeはConfigurationを参照してください。

Operation、Service、Command

config/operations.phpのDiscovery RootはBuild時にOperationを探索します。通常のApplication OperationをProviderへ列挙する必要はありません。PackageやApplication外Sourceを登録する場合だけprovidersを使います。

Typed Self-handled OperationはBuildでHandler Serviceとして自動登録されます。Repository Interface等のApplication固有DependencyをBindingする場合は、Service Providerをconfig/app.phpservicesへ登録します。BuilderのwithOperations()withServices()withCommands()から明示登録を追加することもできます。

Application Maintenance CommandはSymfonyの#[AsCommand]を付け、config/app.phpcommand_discoveryへSource Rootを指定します。build:compileがCommandを探索してCompiled Containerへ登録するため、Required Constructor DependencyをService Providerから注入できます。commandswithCommands()はPackage Command、Instance、明示Override/追加用として維持されます。

QuickstartではOperationをProviderへ列挙せず、Repository Interface、Transactional Command、After Commit Serviceだけを登録します。Default DBAL ConnectionはFrameworkがRuntimeでSynthetic Serviceとして注入するため、ApplicationがCredential付きConnectionをProviderで作る必要はありません。

<?php

declare(strict_types=1);

namespace App;

use App\Feature\Order\CreateOrder\CreateOrderCommand;
use App\Feature\Order\DoctrineOrderRepository;
use App\Feature\Order\OrderRepository;
use App\Feature\Order\RecordOrderCommit;
use App\UserInterface\Http\SampleTokenAuthenticator;
use App\UserInterface\Console\SampleConsoleActorProvider;
use BlackOps\Console\ConsoleActorProvider;
use BlackOps\Core\DependencyInjection\ServiceProvider;
use BlackOps\Core\DependencyInjection\ServiceRegistry;
use BlackOps\Http\Authentication\HttpAuthenticator;

final readonly class ApplicationServiceProvider implements ServiceProvider
{
    public function register(ServiceRegistry $services): void
    {
        $services->autowire(HttpAuthenticator::class, SampleTokenAuthenticator::class);
        $services->autowire(ConsoleActorProvider::class, SampleConsoleActorProvider::class);
        $services->autowire(OrderRepository::class, DoctrineOrderRepository::class);
        $services->autowire(CreateOrderCommand::class);
        $services->autowire(RecordOrderCommit::class);
    }
}

HTTP Process

公式のClassic/Worker EntrypointはBlackOps\Http\SapiRuntimeへApplicationを渡すだけです。

use BlackOps\Http\SapiRuntime;

require dirname(__DIR__) . '/vendor/autoload.php';
$application = require dirname(__DIR__) . '/bootstrap/app.php';
SapiRuntime::run($application); // WorkerはrunWorker($application)

Request生成、Response Emit、Safe 500、Worker LoopはFrameworkが所有します。Application::http()はCustom PSR-15 AdapterやTest向けのEscape Hatchです。

$handler = $application->http();
$response = $handler->handle($serverRequest);

http()は初回呼出時にCompile済みArtifactとDatabase設定を検証し、PSR-15 Handlerを遅延構成します。同じApplicationから繰り返し取得すると同じHandler Instanceを返します。

HTTP構成はSource Discovery、Artifact Compile、Database Migration、DDLを行いません。Artifact不足、Format不正、Build ID不一致時はFallbackせず失敗します。

Console Process

Project Rootのblackopsは同じApplicationからPublic Console Kernelを起動します。

use BlackOps\Application\Application;

require __DIR__ . '/vendor/autoload.php';

/** @var Application $application */
$application = require __DIR__ . '/bootstrap/app.php';

exit($application->console()->run());

Global listの実行境界は一覧形式で異なります。Applicationが明示登録したCommandをクラス名(class-string)で登録すると、Console Kernelを構成するときにCommand実体が生成され、コンストラクタが実行されます。呼び出し側があらかじめ生成したCommand instanceを登録した場合は、その同じinstanceを再利用し、Kernel構成で追加の生成は行いません。どの一覧形式を選んでも、この生成・再利用の境界は変わりません。

Command Manifestから発見したLazy Commandは、通常表示と--rawでは、Command実体を作る処理(factory)を呼び出さずに一覧します。--rawは装飾を省いたテキスト一覧です。

--shortを付けない--format=json|xml|mdでは、引数とOptionの定義(Definition)やHelp取得でCommand実体を作る処理(factory)が呼び出されます。そのfactoryがBuild済みの依存関係を持つ仕組み(Container)からCommand実体を解決する場合があります。個別のhelpも同じようにLazy Commandを解決する場合があります。

そのためGlobal listは、Applicationの初期化やContainerの解決から完全に切り離された診断Commandではありません。旧bin/blackopsblackops:* Prefixは現行の互換入口ではありません。

#[ConsoleCommand]で公開したOperationも同じManifestから登録します。認可主体が必要なApplicationはConsoleActorProviderをService ProviderでBindingしてください。未Bindingまたはactor() === nullではOrigin/Authorization Actorを持たず、#[Authorize]付きOperationは既存Policyで拒否されます。FrameworkはExecution Actorをconsole-runtimeに固定し、CLI OptionからActor IDやCredentialを受け取りません。

Application ObjectやContainerをOperation、Value、Domain Serviceへ渡しません。業務DependencyはConstructor Injectionします。

Session AuthenticationをOpt-in登録する

Framework同梱のSession Coreは、SessionServiceProviderを追加したApplicationだけで有効になります。BearerとCookieは同時に解釈せず、Applicationが一方を選びます。

use App\Infrastructure\Identity\ApplicationSessionIdentityProvider;
use BlackOps\Auth\Session\SessionConfiguration;
use BlackOps\Auth\Session\SessionServiceProvider;

return [
    'services' => [
        SessionServiceProvider::bearer(
            ApplicationSessionIdentityProvider::class,
            new SessionConfiguration(ttlSeconds: 28_800, touchIntervalSeconds: 300),
        ),
    ],
];

make:authconfig/auth.phpは同じSession登録を環境変数から構成する書き方です。app.phpauth.phpの両方で同じService IDを登録すると、後からMergeされるauth.php側が有効になります。登録はどちらか一方だけにしてください。

CookieをCredential Sourceにする場合はSessionServiceProvider::cookie(ApplicationSessionIdentityProvider::class, 'application_session')を使います。Cookieの発行、SecureHttpOnlySameSite、Path/Domain、CSRFはApplicationが所有します。どちらもAuthenticationMiddlewareのGlobal登録は別途必要です。

SessionManagerはLogin/Logout Application ServiceへConstructor Injectionします。issue()が返すRaw Tokenは発行直後にBearer Responseまたは安全なCookieへ変換し、Operation Value、Outcome、Journal、Logへ渡さないでください。rotate()は旧Sessionの失効とSuccessorの発行を一つのTransactionで行い、revoke()はnull/Malformed/Unknown/Expired/Revokedでも安全に完了します。

Session CoreはDefault 8時間のAbsolute TTLとDefault 5分間隔のlast_used_at更新を持ちます。cleanup($cutoff)はCutoffより古いExpired/Revoked Rowだけを削除します。SchemaはRuntimeが自動作成しません。新規Applicationではphp blackops make:authがUser/Session MigrationのImmutable Snapshotを一度だけ生成します。既存Applicationは同じSchema ContractをForward Migrationへ取り込み、Migrationを明示実行してください。