Skip to content

Flyokai

Async PHP application framework on AMPHP 3.x and Revolt — bootstrap lifecycle, HTTP server, CLI, async database drivers, OAuth, ACL, indexer, declarative schema, DTO toolkit, and a DI container designed for module composition.

Flyokai is a metapackage. The framework itself lives in vendor/flyokai/* — every module ships its own README.md, CLAUDE.md, and AGENTS.md. This package is the central place to learn the system: a quickstart, the architecture overview, the module catalog, and pointers into the rest of the docs.

Why Flyokai

  • Cooperative async, end-to-end. HTTP, MySQL (PDO and MySQLi), CSV, OpenSearch, channels — none of them block.
  • DI you can extend across modules. Register routes, CLI commands, ACL resources, indexers, setup steps, repositories without modifying upstream code.
  • DTOs that respect both worlds. Solid for strict, immutable domain objects; Draft / GreyData for flexible inputs and dynamic schemas.
  • Schema as code. Tag a Solid DTO with #[Table]; the schema framework reconciles MySQL on every install/upgrade.
  • Search as code. Tag the same DTO with #[ForeignKey]; criteria queries auto-discover joins.

Quick start

Install

flyokai/flyokai is a metapackage — it provides the central docs and ties the framework modules together, but it is not a project skeleton. Bootstrap a new project from one of the editions:

# HTTP / JSON web API
composer create-project flyokai/webapi-edition my-app dev-dev

# Socket-based async data service (extends webapi-edition)
composer create-project flyokai/data-service-edition my-service dev-dev

cd my-app

If you want the Magento DTOs / cache backend on top of either edition, just composer require flyokai/magento-dto flyokai/magento-amp-mate afterwards. Or composer require flyokai/flyokai to pull every framework module transitively.

First-time setup

vendor/bin/flyok-setup install \
    --db-host=localhost \
    --db-user=app \
    --db-pass=secret \
    --db-name=app \
    --base-url=http://localhost:8080

This deploys bin/flyok-setup, bin/flyok-console, bin/flyok-cluster, runs all DB setup steps, and reconciles the schema from #[Table]-tagged DTOs.

Subsequent operations

# Re-run setup (deploys + db-schema reconcile)
php bin/flyok-setup upgrade

# CLI commands
php bin/flyok-console acl:role:create --name admin '[]'
php bin/flyok-console user:create --uname=admin --email=admin@example.com --role=admin --pass=secret123
php bin/flyok-console oauth:client:create admin client_credentials

# Cluster
php bin/flyok-cluster start
php bin/flyok-cluster stop
php bin/flyok-cluster restart

# Reindex
php bin/flyok-console indexer:reindex

Why two flyok-setups? See docs/cli.md. Initial install uses the vendor script; everything afterwards uses the deployed script (which has absolute paths and the production bootstrap baked in).

Architecture at a glance

Application types

Type Purpose
Setup First-install / upgrade
Cluster Coordinator process
Worker Worker process — serves HTTP and listens for cluster messages (extends Web)
Web Plain HTTP server
Task One-off background tasks
Cli Console commands

Bootstrap lifecycle

Module composer.json autoload calls Registry::addModule()
RootBootstrap(ApplicationType)
   ├── Init phase    — every module's init() registers DI config files
   ├── Build phase   — Amp Injector Application built from merged definitions
   └── Bootstrap     — every module's bootstrap() runs against the live container

HTTP flow

AMPHP SocketHttpServer → Router → HandlerGuard (Authorization) → Controller → JSON Response

Data-service flow

Client → Socket → OAuth Handshake → StreamChannel → Dispatcher → Router → Middleware → Handler → Response

Database layer

Application Config
ConnectionPool (Amp / AsyncPdo / AsyncMysqli / TwoLevel)
Laminas Adapter
Async Driver (suspends fibers, never blocks the loop)

Data pipeline (used by indexer + bulk-import workflows)

DataSource
BatchProcessor
Amplifier Pipeline (Prepare → Load → Validate → Diff → Save)
Bulk DB Operations (InsertOnDuplicate, ID resolvers)

Core concepts

DI (flyokai/amphp-injector)

use Amp\Injector\Application;
use Amp\Injector\Definitions;
use Amp\Injector\Injector;
use function Amp\Injector\{any, arguments, names, object, singleton, value};

$definitions = (new Definitions())
    ->with(singleton(object(MyService::class, arguments(names()
        ->with('config', value(['key' => 'val']))
    ))), 'my_service');

$application = new Application(new Injector(any()), $definitions, 'my-app');
$application->start();

$svc = $application->getContainer()->get('my_service');
  • Definition helperssingleton(), object(), value(), factory(), injectableFactory(), compositionFactory(), compositionItem()
  • Weaversnames(), types(), runtimeTypes(), automaticTypes(), any()
  • Attributes#[ServiceParameter], #[SharedParameter], #[PrivateParameter], #[FactoryParameter(Class)]
  • CompositionsCompositionOrdered with before/after/depends

See the in-framework guide: docs/dependency-injection.md.

DTOs (flyokai/data-mate)

Marker Mutability Construction Use it for
Solid Immutable, public readonly Constructor, validated Domain objects
Draft Mutable, flexible Same DTO class as Solid but relaxed Input staging
GreyData Dynamic key/value $data array API payloads, third-party blobs

fromArray() — Valinor-flexible. cloneWith() — constructor-strict.

Declarative schema (flyokai/db-schema)

#[Table(name: 'flyok_user', alias: 'user')]
#[ForeignKey(name: 'fk_user_role', columns: ['role_id'], referencesDto: RoleSolid::class, referencesColumns: ['role_id'])]
final class UserSolid implements Solid {
    public function __construct(
        #[PrimaryKey(autoIncrement: true)] public readonly int $userId,
        #[Column(length: 64)] public readonly string $username,
        public readonly int $roleId,
    ) {}
}

bin/flyok-setup upgrade reconciles the live database with the declared model on every run. Drops are opt-in (FLYOK_DB_SCHEMA_ALLOW_DESTRUCTIVE=1).

Search criteria (flyokai/search-criteria)

$result = $userRepo->getList([
    'AND' => [
        ['field' => 'status',    'op' => 'eq', 'value' => 'active'],
        ['field' => 'role.name', 'op' => 'in', 'value' => ['admin', 'editor']],
    ],
    'sort' => [['field' => 'created', 'direction' => 'desc']],
    'limit' => 20,
    'withTotal' => true,
]);

role.name auto-discovers the FK and emits an INNER JOIN.

Async never blocks

// ❌ Don't do this in a handler
sleep(1);

// ✅ Do this
Amp\delay(1);

// ✅ Concurrent work
$futures = [Amp\async($a), Amp\async($b), Amp\async($c)];
$results = Amp\Future\await($futures);

Module catalog

Each module has a full README.md linked below. Internal "agent knowledge" is in AGENTS.md next to the README.

Foundation

Module Purpose
flyokai/data-mate Base Dto interface, Solid/Draft/GreyData, identity, enums, collections
flyokai/composition Topological sort for before/after/depends declarations
flyokai/generic State<T>, Builder<T>, Tuner<T>, Execution<T> patterns
flyokai/misc CryptKey, ProfilerFacade, PsrServerAdapter, SharedSequence
flyokai/db-schema Attribute-driven MySQL schema (#[Table], #[Column], #[ForeignKey], …)
flyokai/search-criteria Declarative JSON criteria with auto-join discovery

DI & application

Module Purpose
flyokai/amphp-injector DI container with weavers, compositions, lifecycle
flyokai/application Bootstrap lifecycle, HTTP server, CLI, ACL, DB pools
flyokai/revolt-event-loop Fork of revolt/event-loop adding onMysqli()

Async infrastructure

Module Purpose
flyokai/amp-mate Filesystem helpers, ampFlock
flyokai/amp-channel-dispatcher Request/response RPC over Amp channels
flyokai/amp-data-pipeline Concurrent data processing — sources, processors, batching, multicast
flyokai/amp-csv-reader Streaming CSV parser
flyokai/amp-opensearch Async adapter for the opensearch-php SDK

Database

Module Purpose
flyokai/laminas-db Fork of laminas/laminas-db — sync foundation
flyokai/laminas-db-driver-amp Native AMPHP MySQL driver
flyokai/laminas-db-driver-async AsyncPdo (worker pool) + AsyncMysqli (MYSQLI_ASYNC)
flyokai/laminas-db-bulk-update INSERT … ON DUPLICATE KEY UPDATE, ID resolvers, range chunking
flyokai/zend-db-sql-insertmultiple Multi-row INSERT VALUES builder

Service / console / auth

Module Purpose
flyokai/data-service Socket-based async service layer
flyokai/data-service-message Inter-service request/response DTOs
flyokai/symfony-console Async-friendly Symfony Console with required args / filesystem validators
flyokai/user User auth — DTOs, repository, management
flyokai/oauth-server OAuth 2.0 (league/oauth2-server) — password, client credentials, refresh
flyokai/indexer Search/indexing framework with atomic table swap

Magento

Module Purpose
flyokai/magento-dto Magento DTOs — catalog, sales, inventory, scope, system config
flyokai/magento-amp-mate Async Magento cache backend (CmCacheBackendFile)

Documentation

Framework-level documents in this package's docs/:

Doc Description
docs/getting-started.md 30-minute walkthrough — install → smoke test → first DTO → first endpoint
docs/architecture.md Master diagrams: bootstrap lifecycle, HTTP / data-service flow, DB layer, schema, search-criteria, DI
docs/dependency-injection.md DI config file structure, build flow, services vs definitions, arguments merging, composition pattern
docs/cli.md Which binary to use when (vendor/bin/flyok-setup vs bin/flyok-setup vs bin/flyok-console vs bin/flyok-cluster)
docs/setup-and-deploy.md Install vs upgrade phases, deploy assets, non-interactive install, schema reconcile, production deploy
docs/asynchrony.md The "never block" rules — blocking → async conversion table, concurrency idioms, suspension API
docs/troubleshooting.md Symptoms grouped by layer with the fastest fix
docs/upgrading.md Bumping versions, edition migration, breaking-change protocol
docs/scaffolding.md Skills + commands that scaffold recurring tasks
docs/glossary.md Every flyokai-specific term in one page, linked back to the relevant module
docs/module-naming.md Naming conventions for new modules and editions
docs/composer-repositories.md Inline-repos pain and the recommended Satis migration

Development skills

In .agents/skills/ (also synced to .claude/ and project-root .agents/). Each skill describes prerequisites, scaffolding, conventions, and reference examples for a common task. See docs/scaffolding.md for invocation patterns.

Skill Purpose
new-module Scaffold a complete flyokai module with bootstrap lifecycle
new-endpoint Add HTTP route + controller + auth guard
new-dto Create a DTO following data-mate conventions
new-cli-command Add an async Symfony Console command
new-request-handler Add a data-service socket request handler

Module-specific skills: - flyokai/db-schema/.agents/skills/annotate-dto-schema — tag a Solid DTO with #[Table] and friends - flyokai/search-criteria/.agents/skills/wire-searchable-repository — add getList() / massUpdate() to an existing repository

Module composition cheatsheet

What you want to extend Where to register
HTTP route httpRouterBuilder:default composition
CLI command cli:command:loader composition
Indexer indexerFacade:items composition
ACL resource / role acl:resource:tuner / acl:default-role:tuner
Setup parameter command:install:definition:tuner + command:install:input:tuner
Setup DB step addSetupDbPackageStep() in diconfig_setup.php
DB connection pool implement ConnectionPool, override the alias in diconfig.php
Repository RepositoryContainer composition keyed by entity type
Data-service request handler dataRouterBuilder:default (addRoute)

Standards

  • PHP 8.1+ (8.2+ recommended)
  • AMPHP 3.x, Revolt 1.x
  • MySQL 8.x (the DB drivers and schema framework target it)
  • All I/O is non-blocking; all callbacks must return void/null

License

MIT — Copyright (c) Flyokai (sergey@flyokai.com)

Each vendored fork (flyokai/laminas-db, flyokai/revolt-event-loop, flyokai/amphp-injector, flyokai/zend-db-sql-insertmultiple) carries its upstream license — see the per-module LICENSE file.